1 package org
.argeo
.cms
.internal
.auth
;
3 import java
.nio
.ByteBuffer
;
4 import java
.nio
.CharBuffer
;
5 import java
.nio
.charset
.Charset
;
6 import java
.security
.Principal
;
7 import java
.util
.Arrays
;
11 import javax
.naming
.InvalidNameException
;
12 import javax
.naming
.ldap
.LdapName
;
13 import javax
.security
.auth
.Subject
;
14 import javax
.security
.auth
.callback
.Callback
;
15 import javax
.security
.auth
.callback
.CallbackHandler
;
16 import javax
.security
.auth
.callback
.NameCallback
;
17 import javax
.security
.auth
.callback
.PasswordCallback
;
18 import javax
.security
.auth
.login
.CredentialNotFoundException
;
19 import javax
.security
.auth
.login
.LoginException
;
20 import javax
.security
.auth
.spi
.LoginModule
;
21 import javax
.security
.auth
.x500
.X500Principal
;
23 import org
.apache
.commons
.codec
.binary
.Base64
;
24 import org
.apache
.commons
.codec
.digest
.DigestUtils
;
25 import org
.argeo
.cms
.CmsException
;
26 import org
.argeo
.cms
.KernelHeader
;
27 import org
.argeo
.cms
.internal
.kernel
.Activator
;
28 import org
.osgi
.framework
.BundleContext
;
29 import org
.osgi
.service
.useradmin
.Authorization
;
30 import org
.osgi
.service
.useradmin
.User
;
31 import org
.osgi
.service
.useradmin
.UserAdmin
;
33 public class UserAdminLoginModule
implements LoginModule
{
34 private Subject subject
;
35 private CallbackHandler callbackHandler
;
36 private boolean isAnonymous
= false;
38 private final static LdapName ROLE_USER_NAME
, ROLE_ANONYMOUS_NAME
;
39 private final static X500Principal ROLE_ANONYMOUS_PRINCIPAL
;
42 ROLE_USER_NAME
= new LdapName(KernelHeader
.ROLE_USER
);
43 ROLE_ANONYMOUS_NAME
= new LdapName(KernelHeader
.ROLE_ANONYMOUS
);
44 ROLE_ANONYMOUS_PRINCIPAL
= new X500Principal(
45 ROLE_ANONYMOUS_NAME
.toString());
46 } catch (InvalidNameException e
) {
47 throw new Error("Cannot initialize login module class", e
);
51 private Authorization authorization
;
54 public void initialize(Subject subject
, CallbackHandler callbackHandler
,
55 Map
<String
, ?
> sharedState
, Map
<String
, ?
> options
) {
57 this.subject
= subject
;
58 this.callbackHandler
= callbackHandler
;
59 if (options
.containsKey("anonymous"))
60 isAnonymous
= Boolean
.parseBoolean(options
.get("anonymous")
62 // String ldifFile = options.get("ldifFile").toString();
63 // InputStream in = new URL(ldifFile).openStream();
64 // userAdmin = new LdifUserAdmin(in);
65 } catch (Exception e
) {
66 throw new CmsException("Cannot initialize login module", e
);
71 public boolean login() throws LoginException
{
72 // TODO use a callback in order to get the bundle context
73 BundleContext bc
= Activator
.getBundleContext();
74 UserAdmin userAdmin
= bc
.getService(bc
75 .getServiceReference(UserAdmin
.class));
79 // ask for username and password
80 NameCallback nameCallback
= new NameCallback("User");
81 PasswordCallback passwordCallback
= new PasswordCallback(
85 callbackHandler
.handle(new Callback
[] { nameCallback
,
87 } catch (Exception e
) {
88 throw new CmsException("Cannot handle callbacks", e
);
92 final String username
= nameCallback
.getName();
93 if (username
== null || username
.trim().equals(""))
94 throw new CredentialNotFoundException("No credentials provided");
97 if (passwordCallback
.getPassword() != null)
98 password
= passwordCallback
.getPassword();
100 throw new CredentialNotFoundException("No credentials provided");
102 // user = (User) userAdmin.getRole(username);
103 user
= userAdmin
.getUser(null, username
);
107 byte[] hashedPassword
= ("{SHA}" + Base64
108 .encodeBase64String(DigestUtils
.sha1(toBytes(password
))))
110 if (!user
.hasCredential("userpassword", hashedPassword
))
115 this.authorization
= userAdmin
.getAuthorization(user
);
119 private byte[] toBytes(char[] chars
) {
120 CharBuffer charBuffer
= CharBuffer
.wrap(chars
);
121 ByteBuffer byteBuffer
= Charset
.forName("UTF-8").encode(charBuffer
);
122 byte[] bytes
= Arrays
.copyOfRange(byteBuffer
.array(),
123 byteBuffer
.position(), byteBuffer
.limit());
124 Arrays
.fill(charBuffer
.array(), '\u0000'); // clear sensitive data
125 Arrays
.fill(byteBuffer
.array(), (byte) 0); // clear sensitive data
130 public boolean commit() throws LoginException
{
131 if (authorization
!= null) {
132 Set
<Principal
> principals
= subject
.getPrincipals();
134 String authName
= authorization
.getName();
136 // determine user'S principal
138 final Principal userPrincipal
;
139 if (authName
== null) {
140 name
= ROLE_ANONYMOUS_NAME
;
141 userPrincipal
= ROLE_ANONYMOUS_PRINCIPAL
;
142 principals
.add(userPrincipal
);
144 name
= new LdapName(authName
);
145 userPrincipal
= new X500Principal(name
.toString());
146 principals
.add(userPrincipal
);
147 principals
.add(new ImpliedByPrincipal(ROLE_USER_NAME
,
151 // Add roles provided by authorization
152 for (String role
: authorization
.getRoles()) {
153 LdapName roleName
= new LdapName(role
);
154 if (ROLE_USER_NAME
.equals(roleName
))
155 throw new CmsException(ROLE_USER_NAME
156 + " cannot be listed as role");
157 if (ROLE_ANONYMOUS_NAME
.equals(roleName
))
158 throw new CmsException(ROLE_ANONYMOUS_NAME
159 + " cannot be listed as role");
160 if (roleName
.equals(name
)) {
163 principals
.add(new ImpliedByPrincipal(roleName
164 .toString(), userPrincipal
));
169 } catch (InvalidNameException e
) {
170 throw new CmsException("Cannot commit", e
);
177 public boolean abort() throws LoginException
{
183 public boolean logout() throws LoginException
{
184 // TODO better deal with successive logout
187 // TODO make it less brutal
188 subject
.getPrincipals().removeAll(
189 subject
.getPrincipals(X500Principal
.class));
190 subject
.getPrincipals().removeAll(
191 subject
.getPrincipals(ImpliedByPrincipal
.class));
196 private void cleanUp() {
198 authorization
= null;