View Javadoc
1   package org.argeo.cms.auth;
2   
3   import java.lang.reflect.Method;
4   import java.util.Map;
5   
6   import javax.security.auth.Subject;
7   import javax.security.auth.callback.CallbackHandler;
8   import javax.security.auth.login.LoginException;
9   import javax.security.auth.spi.LoginModule;
10  
11  import org.apache.commons.logging.Log;
12  import org.apache.commons.logging.LogFactory;
13  import org.argeo.cms.internal.kernel.Activator;
14  import org.ietf.jgss.GSSContext;
15  import org.ietf.jgss.GSSCredential;
16  import org.ietf.jgss.GSSException;
17  import org.ietf.jgss.GSSManager;
18  import org.ietf.jgss.GSSName;
19  
20  /** SPNEGO login */
21  public class SpnegoLoginModule implements LoginModule {
22  	private final static Log log = LogFactory.getLog(SpnegoLoginModule.class);
23  
24  	private Subject subject;
25  	private Map<String, Object> sharedState = null;
26  
27  	private GSSContext gssContext = null;
28  
29  	@SuppressWarnings("unchecked")
30  	@Override
31  	public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
32  			Map<String, ?> options) {
33  		this.subject = subject;
34  		this.sharedState = (Map<String, Object>) sharedState;
35  	}
36  
37  	@Override
38  	public boolean login() throws LoginException {
39  		byte[] spnegoToken = (byte[]) sharedState.get(CmsAuthUtils.SHARED_STATE_SPNEGO_TOKEN);
40  		if (spnegoToken == null)
41  			return false;
42  		gssContext = checkToken(spnegoToken);
43  		if (gssContext == null)
44  			return false;
45  		else
46  			return true;
47  		// try {
48  		// String clientName = gssContext.getSrcName().toString();
49  		// String role = clientName.substring(clientName.indexOf('@') + 1);
50  		//
51  		// log.debug("SpnegoUserRealm: established a security context");
52  		// log.debug("Client Principal is: " + gssContext.getSrcName());
53  		// log.debug("Server Principal is: " + gssContext.getTargName());
54  		// log.debug("Client Default Role: " + role);
55  		// } catch (GSSException e) {
56  		// // TODO Auto-generated catch block
57  		// e.printStackTrace();
58  		// }
59  	}
60  
61  	@Override
62  	public boolean commit() throws LoginException {
63  		if (gssContext == null)
64  			return false;
65  
66  		try {
67  			Class<?> gssUtilsClass = Class.forName("com.sun.security.jgss.GSSUtil");
68  			Method createSubjectMethod = gssUtilsClass.getMethod("createSubject", GSSName.class, GSSCredential.class);
69  			Subject gssSubject;
70  			if (gssContext.getCredDelegState())
71  				gssSubject = (Subject) createSubjectMethod.invoke(null, gssContext.getSrcName(),
72  						gssContext.getDelegCred());
73  			else
74  				gssSubject = (Subject) createSubjectMethod.invoke(null, gssContext.getSrcName(), null);
75  			subject.getPrincipals().addAll(gssSubject.getPrincipals());
76  			subject.getPrivateCredentials().addAll(gssSubject.getPrivateCredentials());
77  			return true;
78  		} catch (Exception e) {
79  			throw new LoginException("Cannot commit SPNEGO " + e);
80  		}
81  
82  	}
83  
84  	@Override
85  	public boolean abort() throws LoginException {
86  		if (gssContext != null) {
87  			try {
88  				gssContext.dispose();
89  			} catch (GSSException e) {
90  				if (log.isTraceEnabled())
91  					log.warn("Could not abort", e);
92  			}
93  			gssContext = null;
94  		}
95  		return true;
96  	}
97  
98  	@Override
99  	public boolean logout() throws LoginException {
100 		if (gssContext != null) {
101 			try {
102 				gssContext.dispose();
103 			} catch (GSSException e) {
104 				if (log.isTraceEnabled())
105 					log.warn("Could not abort", e);
106 			}
107 			gssContext = null;
108 		}
109 		return true;
110 	}
111 
112 	private GSSContext checkToken(byte[] authToken) {
113 		GSSManager manager = GSSManager.getInstance();
114 		try {
115 			GSSContext gContext = manager.createContext(Activator.getAcceptorCredentials());
116 
117 			if (gContext == null) {
118 				log.debug("SpnegoUserRealm: failed to establish GSSContext");
119 			} else {
120 				if (gContext.isEstablished())
121 					return gContext;
122 				byte[] outToken = gContext.acceptSecContext(authToken, 0, authToken.length);
123 				if (outToken != null)
124 					sharedState.put(CmsAuthUtils.SHARED_STATE_SPNEGO_OUT_TOKEN, outToken);
125 				if (gContext.isEstablished())
126 					return gContext;
127 			}
128 
129 		} catch (GSSException gsse) {
130 			log.warn(gsse, gsse);
131 		}
132 		return null;
133 
134 	}
135 }