1 package org
.argeo
.cms
.auth
;
5 import javax
.security
.auth
.Subject
;
6 import javax
.security
.auth
.callback
.CallbackHandler
;
7 import javax
.security
.auth
.login
.LoginException
;
8 import javax
.security
.auth
.spi
.LoginModule
;
10 import org
.argeo
.api
.cms
.CmsLog
;
11 import org
.argeo
.cms
.internal
.runtime
.CmsContextImpl
;
12 import org
.ietf
.jgss
.GSSContext
;
13 import org
.ietf
.jgss
.GSSException
;
14 import org
.ietf
.jgss
.GSSManager
;
15 import org
.ietf
.jgss
.GSSName
;
17 import com
.sun
.security
.jgss
.GSSUtil
;
20 public class SpnegoLoginModule
implements LoginModule
{
21 private final static CmsLog log
= CmsLog
.getLog(SpnegoLoginModule
.class);
23 private Subject subject
;
24 private Map
<String
, Object
> sharedState
= null;
26 private GSSContext gssContext
= null;
28 @SuppressWarnings("unchecked")
30 public void initialize(Subject subject
, CallbackHandler callbackHandler
, Map
<String
, ?
> sharedState
,
31 Map
<String
, ?
> options
) {
32 this.subject
= subject
;
33 this.sharedState
= (Map
<String
, Object
>) sharedState
;
37 public boolean login() throws LoginException
{
38 byte[] spnegoToken
= (byte[]) sharedState
.get(CmsAuthUtils
.SHARED_STATE_SPNEGO_TOKEN
);
39 if (spnegoToken
== null) {
40 if (!sharedState
.containsKey(CmsAuthUtils
.SHARED_STATE_NAME
)) {
41 // workaround: set shared state name to empty
42 // in order to avoid Krb5LoginModule printing to System.out
43 // TODO ask upstream to only log in debug mode
44 sharedState
.put(CmsAuthUtils
.SHARED_STATE_NAME
, "");
48 gssContext
= checkToken(spnegoToken
);
49 if (gssContext
== null)
52 if (!sharedState
.containsKey(CmsAuthUtils
.SHARED_STATE_NAME
)) {
54 if (gssContext
.getCredDelegState()) {
55 // commit will succeeed only if we have credential delegation
56 GSSName name
= gssContext
.getSrcName();
57 String username
= name
.toString();
58 sharedState
.put(CmsAuthUtils
.SHARED_STATE_NAME
, username
);
60 } catch (GSSException e
) {
61 throw new IllegalStateException("Cannot retrieve SPNEGO name", e
);
69 public boolean commit() throws LoginException
{
70 if (gssContext
== null)
75 if (gssContext
.getCredDelegState())
76 gssSubject
= (Subject
) GSSUtil
.createSubject(gssContext
.getSrcName(), gssContext
.getDelegCred());
78 gssSubject
= (Subject
) GSSUtil
.createSubject(gssContext
.getSrcName(), null);
79 // without credential delegation we won't have access to the Kerberos key
80 subject
.getPrincipals().addAll(gssSubject
.getPrincipals());
81 subject
.getPrivateCredentials().addAll(gssSubject
.getPrivateCredentials());
83 } catch (Exception e
) {
84 throw new LoginException("Cannot commit SPNEGO " + e
);
90 public boolean abort() throws LoginException
{
91 if (gssContext
!= null) {
94 } catch (GSSException e
) {
95 if (log
.isTraceEnabled())
96 log
.warn("Could not abort", e
);
104 public boolean logout() throws LoginException
{
105 if (gssContext
!= null) {
107 gssContext
.dispose();
108 } catch (GSSException e
) {
109 if (log
.isTraceEnabled())
110 log
.warn("Could not abort", e
);
117 private GSSContext
checkToken(byte[] authToken
) {
118 GSSManager manager
= GSSManager
.getInstance();
120 GSSContext gContext
= manager
.createContext(CmsContextImpl
.getCmsContext().getAcceptorCredentials());
121 if (gContext
== null) {
122 log
.debug("SpnegoUserRealm: failed to establish GSSContext");
124 if (gContext
.isEstablished())
126 byte[] outToken
= gContext
.acceptSecContext(authToken
, 0, authToken
.length
);
127 if (outToken
!= null)
128 sharedState
.put(CmsAuthUtils
.SHARED_STATE_SPNEGO_OUT_TOKEN
, outToken
);
129 if (gContext
.isEstablished())
133 } catch (GSSException gsse
) {
134 log
.warn(gsse
, gsse
);