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 }