This section demonstrates how a password authentication class might be implemented using the PasswordClass. All authentication classes are derived from the LocalAuthenticationClass, so you need to understand the key methods within it:
Authentication classes extend the base class LocalAuthenticationClass as shown on line 12 of PasswordClass Example Code. The LocalAuthenticationClass has a single constructor that must be called as shown in lines 29 - 32. The Identity Server uses this constructor to pass the necessary properties and user store information defined in the Administration Console to the class.
The LocalAuthenticationClass defines a single abstract method, doAuthenticate(), which must be implemented by new classes. During user authentication, the Identity Server creates an instance of an authentication class and calls the authenticate() method, which in turn calls the doAuthenticate() method. By default, the class instance remains persistent, allowing the state to be preserved between requests/responses while credentials are obtained. If persistence is not needed, the mustPersist() method can be overloaded to return False so new instances of the class are created upon each call to the authenticate() method.
Lines 76 - 116 in the PasswordClass Example Code show how the doAuthenticate() method is used. Return values from this method indicate to the Identity Server that the class has succeeded or failed to authenticate a user or that additional user credentials are required and must be obtained.
The call to the isFirstCallAfterPrevMethod() method on line 84 determines if the call to the class is following a successful authentication by another class executed by a method. If that is the case, any credentials provided for the previous class most likely are not valid for this class and should not be tested for (line 88). In this example, the handlePostedData() method is called to obtain and validate a username and password entered by a user.
When lines 93 - 115 are encountered in the PasswordClass Example Code, it has been determined that a page needs to be returned via the execution of a JSP to enable credentials to be prompted for and returned. Tests are made to determine if provisioning should be enabled, and if a button and federated providers should be displayed. The return value of HANDLED_REQUEST indicates that the class has responded to the request and requires more information to proceed.
The handlePostedData() method does much of the important work of this example (lines 147 - 191 in the PasswordClass Example Code). Lines 151 - 153 check to see if canceling the authentication should occur. Lines 156 - 157 attempt to obtain the credentials.
Line 160 provides an example of obtaining a class property configured by an administrator. In this case, a query can be defined by the administrator that can be used to look up a user instead of using the username and password. If the query is used, the authenticateWithQuery method is called at line 166. If a query is not available, the authenticateWithPassword() method is called at line 176.
If the credentials correctly identify the user, the value AUTHENTICATED is returned. If they fail to identify the user, NOT_AUTHENTICATED is returned.
When eDirectory is the user store and a password has either expired or is expiring, the return values PWD_EXPIRED and PWD_EXPIRING can be returned respectively. See lines 180-186.
Line 189 demonstrates how an attribute is used to set an error message that is displayed to the user by calling the method getUserErrorMsg().
1 package com.novell.nidp.authentication.local; 2 3 import java.util.*; 4 5 import com.novell.nidp.*; 6 import com.novell.nidp.authentication.*; 7 import com.novell.nidp.common.authority.*; 8 9 /** An example of the implementation of LocalAuthenticationClass. 10 */ 11 12 public class PasswordClass extends LocalAuthenticationClass 13 { 14 /** 15 * *** 16 * 17 */ 18 19 private static final String CANCEL_X = "Cancel.x"; 20 /** 21 * Constructs the form-based authentication methods. 22 * 23 * @param props Properties associated with the implementing 24 class. 25 * @param uStores List of ordered user stores to authenticate 26 * against. 27 */ 28 29 public PasswordClass(Properties props, ArrayList uStores) 30 { 31 super(props,uStores); 32 } 33 34 /** 35 * Gets the authentication type this class implements. 36 * 37 * @return The authentication type represented by this class. 38 */ 39 public String getType() 40 { 41 return AuthnConstants.PASSWORD; 42 } 43 44 /** Performs form-based authentication. This method gets called 45 * on each response 46 * during the authentication process. 47 * 48 * @return Returns the status of the authentication process: 49 * 50 * * AUTHENTICATED: Specifies that the authentication 51 * succeeded in identifying a single NIDPPrincipal object 52 * (user). 53 * * NOT_AUTHENTICATED: Specifies that the authentication 54 * failed. 55 * * CANCELLED: Specifies that the authentication process was 56 * canceled. This typically occurs only during authentication 57 * after a request from a service provider. 58 * * HANDLED_REQUEST: The request has been handled and 59 * a response 60 * provided. Further processing or information is needed to 61 * complete authentication. Typically, this value is returned 62 * when a page is returned that will query for credentials. 63 * * PWD_EXPIRING: Successful authentication but the user's 64 * password is about to expire. This condition results in a 65 * redirection to the expired password servlet (if it is 66 66 * defined on the authentication contract). 67 * * PWD_EXPIRED: Successful authentication but the user's 68 * password is expired. This condition results in a 69 * redirection to expired password servlet (if it is defined 70 * on the authentication contract). 71 * 72 * @throws NIDPException Specifies how the authentication 73 * process proceeds***. 74 */ 75 76 protected int doAuthenticate() 77 throws NIDPException 78 { 79 // If this is the first time the class is called following 80 // another method, we want to display the form that will get 81 // the credentials. This method prevents a previous form from 82 // providing data to the next form if any parameter names end 83 // up being the same. 84 if (!isFirstCallAfterPrevMethod()) 85 { 86 // This wasn't first time the method was called, so see if 87 // data can be processed. 88 int status = handlePostedData(); 89 if (status != NOT_AUTHENTICATED) 90 return status; 91 } 92 93 // If this is an active login, display login page 94 if (getProvisionURL() != null) 95 96 m_Request.setAttribute(NIDPConstants.RESP_ATTR_PROVISION, getProvisionURL()); 97 98 if (isCancelAppropriate()) 99 m_Request.setAttribute(NIDPConstants.RESP_ATTR_CANCEL, NIDPConstants.VALUE_TRUE); 100 101 if (isUserIdentification()) 102 m_Request.setAttribute(NIDPConstants.RESP_ATTR_IDENTIFY, NIDPConstants.VALUE_TRUE); 103 104 // If we are just identifying the user, we do not show 105 federatable providers. 106 else 107 m_Request.setAttribute(NIDPConstants.RESP_ATTR_PROVIDERS, getIDPProvide rs()); 108 109 String jsp = getProperty(AuthnConstants.PROPERTY_JSP); 110 if (jsp == null || jsp.length() == 0) 111 jsp = NIDPConstants.JSP_LOGIN; 112 113 m_Request.setAttribute(NIDPConstants.ATTR_URL, (getReturnURL() != null ? getReturnURL() : m_Request.getRequestURL().toString())); 114 showJSP(jsp); 115 return HANDLED_REQUEST; 116 } 117 118 /** 119 * Get and process the data that is posted from the form. 120 * 121 * @return Returns the status of the authentication process 122 * which is one of the following values: 123 * 124 * * AUTHENTICATED: Specifies that the authentication 125 * succeeded in identifying a single NIDPPrincipal object 126 * (user). 127 * * NOT_AUTHENTICATED: Specifies that the authentication 128 * failed. 129 * * CANCELLED: Specifies that the authentication process was 130 * canceled. This typically occurs only during authentication 131 * after a request from a service provider. 132 * * HANDLED_REQUEST: The request has been handled and 133 * a response provided. Further processing or information is 134 * is needed to complete authentication. Typically, this 135 * value is returned when a page is returned that will 136 * query for credentials. 137 * * PWD_EXPIRING: Successful authentication but the 138 * user's password is about to expire. This condition results 139 * in a redirection to the expired password servlet (if it 140 * is defined on the authentication contract). 141 * * PWD_EXPIRED: Successful authentication but the 142 * user's password is expired. This condition results in a 143 * redirection to expired password servlet (if it is defined 144 * on the authentication contract). 145 */ 146 147 private int handlePostedData() 148 { 149 String cancel = m_Request.getParameter(CANCEL_X); 150 151 // If we got a cancel and we are to check for a cancel. 152 if (cancel != null && isCancelAppropriate()) 153 return CANCEL; 154 155 // Look for a name and password. 156 String id = m_Request.getParameter (NIDPConstants.PARM_USERID); 157 String password = m_Request.getParameter (NIDPConstants.PARM_PASSWORD); 158 159 // Check to see if admin has setup for a custom query. 160 String query = getProperty(AuthnConstants.PROPERTY_QUERY); 161 boolean hasQuery = (query != null && query.length() > 0); 162 163 try 164 { 165 // Using admin defined attributes for query. 166 if (hasQuery && authenticateWithQuery (getLDAPQueryString(query),password)) 167 return AUTHENTICATED; 169 170 // If using default of name and password. 171 else if (!hasQuery) 172 { 173 if (id == null || id.length() == 0) 174 return NOT_AUTHENTICATED; 175 176 if (authenticateWithPassword(id,password)) 177 return AUTHENTICATED; 178 } 179 } 180 catch (PasswordExpiringException pe) 181 { 182 return PWD_EXPIRING; 183 } 184 catch (PasswordExpiredException pe) 185 { 186 return PWD_EXPIRED; 187 } 188 189 m_Request.setAttribute (NIDPConstants.ATTR_LOGIN_ERROR, getUserErrorMsg()); 190 return NOT_AUTHENTICATED; 191 } 192 193 /** Gets a representative LDAP query to find a user 194 * in a directory***. 195 * 196 * @return Returns an LDAP query form string that can be used 197 * to search a directory. 198 * @param query */ 199 private String getLDAPQueryString(String query) 200 { 201 StringBuffer buf = new StringBuffer(); 202 int idx = 0; 203 int idx2 = 0; 204 do 205 { 206 idx2 = query.indexOf("%",idx); 207 if (idx2 != -1) 208 { 209 buf.append(query.substring(idx,idx2)); 210 int idx3 = query.indexOf("%",idx2+1); 211 if (idx3 != -1) 212 { 213 String param = query.substring(idx2+1,idx3); 214 String value = m_Request.getParameter(param); 215 if (value != null && value.length() > 0) 216 buf.append(value); 217 218 idx = idx3 + 1; 219 } 220 } 221 else 222 buf.append(query.substring(idx)); 223 224 } while(idx2 != -1); 225 226 return buf.toString(); 227 } 228 }