View Javadoc

1   /***
2    *  Copyright 2003-2007 Greg Luck
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.jpam;
18  
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  
22  /***
23   * The PAM bridging class. Most of the work is done here.
24   * <p/>
25   * To see debugging output for this class and native code, set the installed logging toolkit level
26   * for this class to DEBUG or equivalent. The debugging output for the native code will
27   * be sent to <code>STDOUT</code>.
28   * <p/>
29   * This class may be called directly, or by using JAAS, via the {@link net.sf.jpam.jaas.JpamLoginModule}.
30   *
31   * @author <a href="mailto:gregluck@users.sourceforge.net">Greg Luck</a>
32   * @author David Lutterkort, RedHat
33   * @author Ken Huffman
34   * @version $Id: Pam.java 20 2007-04-15 00:46:53Z gregluck $
35   *
36   */
37  public class Pam {
38      private static final Log LOG = LogFactory.getLog(Pam.class.getName());
39      private static final String JPAM_SHARED_LIBRARY_NAME = "jpam";
40      private String serviceName;
41  
42  
43      /***
44       * The default service name of "net-sf-pam".
45       * <p/>
46       * This service is expected to be configured in /etc/pam.d
47       */
48      public static final String DEFAULT_SERVICE_NAME = "net-sf-" + JPAM_SHARED_LIBRARY_NAME;
49  
50      static {
51              System.loadLibrary(JPAM_SHARED_LIBRARY_NAME);
52      }
53  
54  
55      /***
56       * Creates a new Pam object configured to use the {@link #DEFAULT_SERVICE_NAME}
57       */
58      public Pam() {
59          this(DEFAULT_SERVICE_NAME);
60      }
61  
62      /***
63       * Creates a new PAM object configured with the specified service name.
64       * <p/>
65       * A file with the same name must exist in /etc/pam.d
66       *
67       * @param serviceName
68       * @throws NullPointerException
69       * @throws IllegalArgumentException
70       */
71      public Pam(String serviceName) throws NullPointerException, IllegalArgumentException {
72          if (serviceName == null) {
73              throw new NullPointerException("Service name is null");
74          } else if (serviceName.length() == 0) {
75              throw new IllegalArgumentException("Service name is empty");
76          }
77          this.serviceName = serviceName;
78      }
79  
80      /***
81       * A simple way to check that JNI is installed and properly works
82       *
83       * @return true if working
84       */
85      native boolean isSharedLibraryWorking();
86  
87      /***
88       * The {@link #isSharedLibraryWorking()} native method callsback to this method to make sure all is well.
89       */
90      private void callback() {
91          //noop
92      }
93  
94      /***
95       * Authenticates a user.
96       * <p/>
97       * This method is threadsafe.
98       * <p/>
99       * If the logging toolkit is set to DEBUG, the shared library will emit debug
100      * information to the console.
101      *
102      * @param username    the username to be authenticated
103      * @param credentials the credentials to use in the authentication .e.g a password
104      * @return true if the <code>PamReturnValue</code> is {@link PamReturnValue#PAM_SUCCESS}
105      */
106     public boolean authenticateSuccessful(String username, String credentials) {
107         PamReturnValue success = PamReturnValue.PAM_SUCCESS;
108         PamReturnValue actual = authenticate(username, credentials);
109         return actual.equals(success);
110     }
111 
112     /***
113      * Sames as <code>authenticateSuccessful</code>, except a {@link PamReturnValue} is returned
114      * <p/>
115      * This method is threadsafe.
116      * @param username
117      * @param credentials
118      * @return a PAM specific return value
119      * @throws NullPointerException if any of the parameters are null
120      * @see #authenticateSuccessful(String, String)
121      */
122     public PamReturnValue authenticate(String username, String credentials) throws NullPointerException {
123         boolean debug = LOG.isDebugEnabled();
124         LOG.debug("Debug mode active.");
125         if (serviceName == null) {
126             throw new NullPointerException("Service name is null");
127         } else if (username == null) {
128             throw new NullPointerException("User name is null");
129         } else if (credentials == null) {
130             throw new NullPointerException("Credentials are null");
131         }
132         synchronized (Pam.class) {
133             PamReturnValue pamReturnValue = PamReturnValue.fromId(authenticate(serviceName, username, credentials, debug));
134             return pamReturnValue;
135         }
136     }
137 
138 
139     /***
140      * A main method
141      */
142     public static void main(String[] args) {
143         Pam pam = new Pam();
144         PamReturnValue pamReturnValue = pam.authenticate(args[0], args[1]);
145         System.out.println("Response: " + pamReturnValue);
146     }
147 
148     /***
149      * Authenticates a user.
150      *
151      * Warning: Any calls to this method should be synchronized on the class. The underlying PAM mechanism is not
152      * threadsafe.
153      *
154      * @param serviceName the pam.d config file to use
155      * @param username    the username to be authenticated
156      * @param credentials the credentials to be authenticated
157      * @param debug       if true, debugging information will be emitted
158      * @return an integer, which can be converted to a {@link PamReturnValue} using {@link PamReturnValue#fromId(int)}
159      */
160     private native int authenticate(String serviceName, String username, String credentials, boolean debug);
161 
162     /***
163      * @return the system dependent name of the shared library the Pam class is expecting.
164      */
165     public static String getLibraryName() {
166         return System.mapLibraryName(JPAM_SHARED_LIBRARY_NAME);
167     }
168 
169 
170     /***
171      * @return the servicename this PAM object is using
172      */
173     public String getServiceName() {
174         return serviceName;
175     }
176 }