KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > security > srp > jaas > SRPCacheLoginModule


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.security.srp.jaas;
23
24 import java.security.Principal JavaDoc;
25 import java.util.Arrays JavaDoc;
26 import java.util.Map JavaDoc;
27 import java.util.Set JavaDoc;
28 import javax.crypto.spec.SecretKeySpec;
29 import javax.naming.InitialContext JavaDoc;
30 import javax.naming.NamingException JavaDoc;
31 import javax.security.auth.Subject JavaDoc;
32 import javax.security.auth.callback.CallbackHandler JavaDoc;
33 import javax.security.auth.callback.Callback JavaDoc;
34 import javax.security.auth.callback.UnsupportedCallbackException JavaDoc;
35 import javax.security.auth.login.LoginException JavaDoc;
36 import javax.security.auth.spi.LoginModule JavaDoc;
37
38 import org.jboss.logging.Logger;
39 import org.jboss.security.auth.callback.SecurityAssociationCallback;
40 import org.jboss.security.srp.SRPParameters;
41 import org.jboss.security.srp.SRPServerSession;
42 import org.jboss.security.srp.SRPSessionKey;
43 import org.jboss.util.CachePolicy;
44
45 /** A server side login module that validates a username and
46  session client challenge response against the cache of authentication
47  info maintained by the SRPService mbean. This module needs
48  a CallbackHandler that supplies the user principal and
49  credential via the SecurityAssociationCallback object.
50  
51  module options:
52  cacheJndiName, the JNDI name of the CachePolicy of <Principal,SRPServerSession>
53  information managed by the SRPSerice.
54  domainName,
55  
56  @author Scott.Stark@jboss.org
57  @version $Revision: 40096 $
58  */

59 public class SRPCacheLoginModule implements LoginModule JavaDoc
60 {
61    private static Logger log = Logger.getLogger(SRPCacheLoginModule.class);
62    private Subject JavaDoc subject;
63    private CallbackHandler JavaDoc handler;
64    private Map JavaDoc sharedState;
65    private String JavaDoc domainName;
66    private String JavaDoc cacheJndiName;
67    private byte[] clientChallenge;
68    private SRPServerSession session;
69    private Principal JavaDoc userPrincipal;
70    private boolean loginFailed;
71    
72    public SRPCacheLoginModule()
73    {
74    }
75    
76    // --- Begin LoginModule interface methods
77
/** Initialize the login module.
78     @param subject, the subject to authenticate
79     @param handler, the app CallbackHandler used to obtain username & password
80     @param sharedState, used to propagate the authenticated principal and
81     credential hash.
82     @param options, the login module options. These include:
83     cacheJndiName: the JNDI name of the CachePolicy of <Principal,Subject>
84     information managed by the SRPSerice.
85     domainName: the security domain name.
86     */

87    public void initialize(Subject JavaDoc subject, CallbackHandler JavaDoc handler, Map JavaDoc sharedState, Map JavaDoc options)
88    {
89       this.subject = subject;
90       this.handler = handler;
91       this.sharedState = sharedState;
92       cacheJndiName = (String JavaDoc) options.get("cacheJndiName");
93       log.trace("cacheJndiName="+cacheJndiName);
94       domainName = (String JavaDoc) options.get("domainName");
95    }
96    
97    /** Access the user Principal object and credentials by passing a
98     SecurityAssociationCallback object to the registered CallbackHandler. This
99     method then validates the user by looking up the cache information using
100     the Principal object as the key and compares the cache credential against the
101     the credential obtained from the SecurityAssociationCallback. The
102     login credential should be the M1 verifcation challenge byte[].
103     
104     @return true is login succeeds, false if login does not apply.
105     @exception LoginException, thrown on login failure.
106     */

107    public boolean login() throws LoginException JavaDoc
108    {
109       loginFailed = true;
110       getUserInfo();
111       
112       String JavaDoc username = userPrincipal.getName();
113       // First try to locate an SRPServerInterface using JNDI
114
try
115       {
116          if( cacheJndiName == null )
117             throw new LoginException JavaDoc("Required cacheJndiName option not set");
118          InitialContext JavaDoc iniCtx = new InitialContext JavaDoc();
119          CachePolicy cache = (CachePolicy) iniCtx.lookup(cacheJndiName);
120          SRPSessionKey key;
121          if( userPrincipal instanceof SRPPrincipal )
122          {
123             SRPPrincipal srpPrincpal = (SRPPrincipal) userPrincipal;
124             key = new SRPSessionKey(username, srpPrincpal.getSessionID());
125          }
126          else
127          {
128             key = new SRPSessionKey(username);
129          }
130          Object JavaDoc cacheCredential = cache.get(key);
131          if( cacheCredential == null )
132          {
133             throw new LoginException JavaDoc("No SRP session found for: "+key);
134          }
135          log.trace("Found SRP cache credential: "+cacheCredential);
136          /** The cache object should be the SRPServerSession object used in the
137           authentication of the client.
138           */

139          if( cacheCredential instanceof SRPServerSession )
140          {
141             session = (SRPServerSession) cacheCredential;
142             if( validateCache(session) == false )
143                throw new LoginException JavaDoc("Failed to validate SRP session key for: "+key);
144          }
145          else
146          {
147             throw new LoginException JavaDoc("Unknown type of cache credential: "+cacheCredential.getClass());
148          }
149       }
150       catch(NamingException JavaDoc e)
151       {
152          log.error("Failed to load SRP auth cache", e);
153          throw new LoginException JavaDoc("Failed to load SRP auth cache: "+e.toString(true));
154       }
155       
156       log.trace("Login succeeded");
157       // Put the username and the client challenge into the sharedState map
158
sharedState.put("javax.security.auth.login.name", username);
159       sharedState.put("javax.security.auth.login.password", clientChallenge);
160       loginFailed = false;
161       return true;
162    }
163    
164    /** All login modules have completed the login() phase, commit if we
165     succeeded. This entails adding the princial to the subject Principals set.
166     It also adds the client challenge response to the PublicCredentials set
167     and the private session key to the PrivateCredentials set as a SecretKeySpec.
168     @return false, if the login() failed, true if the commit succeeds.
169     @exception LoginException, thrown on failure to add the principal.
170     */

171    public boolean commit() throws LoginException JavaDoc
172    {
173       if( loginFailed == true )
174          return false;
175       Set JavaDoc principals = subject.getPrincipals();
176       principals.add(userPrincipal);
177       subject.getPublicCredentials().add(clientChallenge);
178       byte[] sessionKey = session.getSessionKey();
179       SRPParameters params = session.getParameters();
180       Set JavaDoc privateCredentials = subject.getPrivateCredentials();
181       privateCredentials.add(params);
182       if( params.cipherAlgorithm != null )
183       {
184          SecretKeySpec secretKey = new SecretKeySpec(sessionKey, params.cipherAlgorithm);
185          privateCredentials.add(secretKey);
186       }
187       else
188       {
189          privateCredentials.add(sessionKey);
190       }
191
192       return true;
193    }
194
195    public boolean abort() throws LoginException JavaDoc
196    {
197       userPrincipal = null;
198       clientChallenge = null;
199       return true;
200    }
201
202    /** Remove the userPrincipal, clientChallenge and sessionKey associated
203     with the subject during commit().
204     @return true always.
205     @exception LoginException, thrown on exception during remove of the Principal
206     added during the commit.
207     */

208    public boolean logout() throws LoginException JavaDoc
209    {
210       try
211       {
212          if( subject.isReadOnly() == false )
213          { // Remove userPrincipal
214
Set JavaDoc s = subject.getPrincipals(userPrincipal.getClass());
215             s.remove(userPrincipal);
216             subject.getPublicCredentials().remove(clientChallenge);
217             byte[] sessionKey = session.getSessionKey();
218             SRPParameters params = session.getParameters();
219             Set JavaDoc privateCredentials = subject.getPrivateCredentials();
220             if( params.cipherAlgorithm != null )
221             {
222                SecretKeySpec secretKey = new SecretKeySpec(sessionKey, params.cipherAlgorithm);
223                privateCredentials.remove(secretKey);
224             }
225             else
226             {
227                privateCredentials.remove(sessionKey);
228             }
229             privateCredentials.remove(params);
230          }
231       }
232       catch(Exception JavaDoc e)
233       {
234          throw new LoginException JavaDoc("Failed to remove commit information, "+e.getMessage());
235       }
236       return true;
237    }
238    
239 // --- End LoginModule interface methods
240

241    /** Obtain the Principal and credentials that are to be authenticated.
242     */

243    private void getUserInfo() throws LoginException JavaDoc
244    {
245       // Get the security association info
246
if( handler == null )
247          throw new LoginException JavaDoc("No CallbackHandler provied");
248
249       SecurityAssociationCallback sac = new SecurityAssociationCallback();
250       Callback JavaDoc[] callbacks = { sac };
251       try
252       {
253          handler.handle(callbacks);
254          userPrincipal = sac.getPrincipal();
255          clientChallenge = (byte[]) sac.getCredential();
256          sac.clearCredential();
257       }
258       catch(java.io.IOException JavaDoc e)
259       {
260          throw new LoginException JavaDoc(e.toString());
261       }
262       catch(UnsupportedCallbackException JavaDoc uce)
263       {
264          throw new LoginException JavaDoc("UnsupportedCallback: " + uce.getCallback().toString());
265       }
266       catch(ClassCastException JavaDoc e)
267       {
268          throw new LoginException JavaDoc("Credential info is not of type byte[], "+ e.getMessage());
269       }
270    }
271    
272    /** This method obtains the session getClientResponse() value which
273     contains the challenge the client used to verify the session key.
274     */

275    private boolean validateCache(SRPServerSession session)
276    {
277       byte[] challenge = session.getClientResponse();
278       boolean isValid = Arrays.equals(challenge, clientChallenge);
279       return isValid;
280    }
281    
282 }
283
Popular Tags