1 package no.feide.mellon.jaas.loginmodules; 2 3 4 import java.util.Map; 5 import java.util.*; 6 7 import java.security.Principal; 8 import javax.security.auth.Subject; 9 import javax.security.auth.callback.*; 10 import javax.security.auth.login.FailedLoginException; 11 import javax.security.auth.login.LoginException; 12 import javax.security.auth.spi.LoginModule; 13 14 import no.feide.mellon.jaas.callbackhandlers.*; 15 import no.feide.mellon.jaas.principals.*; 16 import no.feide.mellon.v2_1.*; 17 import no.feide.moria.webservices.v2_1.Attribute; 18 19 /*** 20 * @author Rikke Amilde Løvlid 21 */ 22 public class MoriaLoginModule implements LoginModule{ 23 24 private Subject subject; 25 private CallbackHandler callbackHandler; 26 private Map sharedState; 27 private Map options; 28 29 private boolean loginSucceeded; 30 private boolean commitSucceeded; 31 32 private String username; 33 private ArrayList tmpPrincipals; 34 private ArrayList tmpPublicCredentials; 35 36 private boolean debug; 37 38 private final static String[] ATTRIBUTE_NAMES = {"eduPersonAffiliation", "eduPersonScopedAffiliation", "eduPersonPrimaryAffiliation"}; 39 private String endpoint; 40 private String service_username; 41 private String service_password; 42 43 public MoriaLoginModule(){ 44 tmpPrincipals = new ArrayList(); 45 tmpPublicCredentials = new ArrayList(); 46 loginSucceeded = false; 47 commitSucceeded = false; 48 debug = false; 49 } 50 51 /*** 52 * Initialize this <code>LoginModule</code> 53 * <br><br> 54 * @param subject the <code>Subject</code> to be authenticated. 55 * @param callbackHandler a <code>CallbackHandler</code> for communicating with the user, 56 * (promting for username and password) 57 * @param sharedState state shared with the other <code>LoginModule</code> 58 * @param options options specified in the login <code>Configuration</code> for this 59 * particular <code>LoginModule</code> 60 */ 61 public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options){ 62 this.subject = subject; 63 this.callbackHandler = callbackHandler; 64 this.sharedState = sharedState; 65 this.options = options; 66 67 if(options.containsKey("debug")){ 68 debug = "true".equalsIgnoreCase((String)options.get("debug")); 69 } 70 71 endpoint = (String)options.get("endpoint"); 72 service_username = (String)options.get("service_username"); 73 service_password = (String)options.get("service_password"); 74 75 if(debug){ 76 System.out.println("\t[MoriaLoginModule] initialize"); 77 } 78 } 79 80 /*** 81 * The login method is called to authenticate the user. 82 * 83 * @return true if the authentication succeedes (no exception is thrown). 84 * 85 * @throws FailedLoginException if authentication failes. 86 * @throws LoginException if this <code>LoginModule</code> is unable to perform the uthentication. 87 */ 88 public boolean login() throws LoginException{ 89 90 if(debug){ 91 System.out.println("\t[MoriaLoginModule] login"); 92 } 93 94 if(callbackHandler == null){ 95 throw new LoginException("Error: no CallbackHandler available"); 96 } 97 98 try{ 99 Callback[] callbacks = new Callback[2]; 100 callbacks[0] = new NameCallback("username: "); 101 callbacks[1] = new PasswordCallback("password: ", false); 102 103 callbackHandler.handle(callbacks); 104 105 username = ((NameCallback)callbacks[0]).getName(); 106 107 char[] password = ((PasswordCallback)callbacks[1]).getPassword(); 108 109 ((PasswordCallback)callbacks[1]).clearPassword(); 110 callbacks[0] = null; 111 callbacks[1] = null; 112 113 if(debug){ 114 System.out.println("\t[MoriaLoginModule] " + "user entered user name: " + username); 115 System.out.print("\t[MoriaLoginModule] " + "user entered password: "); 116 for(int i=0; i<password.length; i++){ 117 System.out.print(password[i]); 118 } 119 System.out.println(); 120 } 121 122 loginSucceeded = validate(username, password); 123 124 if(loginSucceeded){ 125 if(debug){ 126 System.out.println("\t[MoriaLoginModule] authentication succeeded"); 127 } 128 return true; 129 } 130 else{ 131 if(debug){ 132 System.out.println("\t[MoriaLoginModule] authentication failed"); 133 } 134 username = null; 135 throw new FailedLoginException("Authentication failed"); 136 } 137 } 138 catch(LoginException le){ 139 loginSucceeded = false; 140 throw le; 141 } 142 catch(Exception e){ 143 loginSucceeded = false; 144 throw new LoginException(e.getMessage()); 145 } 146 147 } 148 149 /*** 150 * This method is called if the LoginContext's overall authentication succeeded. 151 * 152 * @return true if this loginmodules own login attempt succeded and commit succeeds, 153 * @return false if the login attempt failed. 154 * 155 * @throws LoginException if the commit attempt failes. 156 */ 157 public boolean commit() throws LoginException{ 158 if(debug){ 159 System.out.println("\t[MoriaLoginModule] commit"); 160 } 161 162 if(loginSucceeded){ 163 if(subject.isReadOnly()){ 164 throw new LoginException("Subject is Readonly"); 165 } 166 167 try{ 168 if(debug){ 169 Iterator it = tmpPrincipals.iterator(); 170 while(it.hasNext()){ 171 System.out.println("\t[MoriaLoginModule] Principal: " + it.next().toString()); 172 } 173 } 174 subject.getPrincipals().addAll(tmpPrincipals); 175 subject.getPublicCredentials().addAll(tmpPublicCredentials); 176 177 tmpPrincipals.clear(); 178 tmpPublicCredentials.clear(); 179 180 if(callbackHandler instanceof PassiveCallbackHandler){ 181 ((PassiveCallbackHandler)callbackHandler).clearPassword(); 182 } 183 184 commitSucceeded = true; 185 186 return true; 187 } 188 catch(Exception ex){ 189 throw new LoginException(ex.getMessage()); 190 } 191 } 192 else{ 193 tmpPrincipals.clear(); 194 tmpPublicCredentials.clear(); 195 return false; 196 } 197 } 198 199 /*** 200 * This method is called if the LoginContext's overall authentication failed. 201 * 202 * @return false if this loginmodules own login attempts failed 203 * @return true otherwise 204 * 205 * @throws LoginException if the abort failes 206 */ 207 public boolean abort() throws LoginException{ 208 if(debug){ 209 System.out.println("\t[MoriaLoginModule] abort"); 210 } 211 212 if(!loginSucceeded){ 213 return false; 214 } 215 else if(loginSucceeded && !commitSucceeded){ 216 loginSucceeded = false; 217 username = null; 218 tmpPrincipals.clear(); 219 tmpPublicCredentials.clear(); 220 221 if(callbackHandler instanceof PassiveCallbackHandler){ 222 ((PassiveCallbackHandler)callbackHandler).clearPassword(); 223 } 224 } 225 else{ 226 logout(); 227 } 228 229 return true; 230 } 231 232 /*** 233 * This method removes the principals that was added by the <code>commit</code> method. 234 * 235 * @return true in all cases. 236 * 237 * @throws LoginException if the logout fails. 238 */ 239 public boolean logout() throws LoginException{ 240 if(debug){ 241 System.out.println("\t[MoriaLoginModule] logout"); 242 } 243 244 tmpPrincipals.clear(); 245 tmpPublicCredentials.clear(); 246 247 if(callbackHandler instanceof PassiveCallbackHandler){ 248 ((PassiveCallbackHandler)callbackHandler).clearPassword(); 249 } 250 251 Iterator it = subject.getPrincipals().iterator(); 252 while(it.hasNext()){ 253 Principal p = (Principal)it.next(); 254 if(debug){ 255 System.out.println("\t[MoriaLoginModule] removing principal " + p.toString()); 256 } 257 it.remove(); 258 } 259 260 it = subject.getPublicCredentials().iterator(); 261 while(it.hasNext()){ 262 Object c = it.next(); 263 if(debug){ 264 System.out.println("\t[MoriaLoginModule] removing credential " + c.toString()); 265 } 266 it.remove(); 267 } 268 269 return true; 270 } 271 272 /*** 273 * This method checks the username and password and gets the users attribute values. 274 * 275 * @param username 276 * @param password 277 * 278 * @return true if username and password are correct and false if there are som exception or the 279 * username and/or password not is correct. 280 */ 281 private boolean validate(String username, char[] password){ 282 try{ 283 Moria service = new Moria(endpoint, service_username, service_password); 284 285 Attribute[] attributes = service.directNonInteractiveAuthentication(ATTRIBUTE_NAMES, username, new String(password)); 286 287 for(int i=0; i<attributes.length; i++){ 288 Attribute att = attributes[i]; 289 for(int j=0; j<att.getValues().length; j++){ 290 tmpPrincipals.add(new MoriaPrincipal(att.getName(), att.getValues()[j])); 291 } 292 } 293 tmpPublicCredentials.add(username); 294 295 return true; 296 } 297 catch(Exception ex){ 298 System.err.println("Error: " + ex.getMessage()); 299 ex.printStackTrace(); 300 return false; 301 } 302 } 303 }