2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org
.argeo
.security
.ldap
;
19 import java
.util
.Collections
;
20 import java
.util
.List
;
22 import java
.util
.TreeSet
;
24 import javax
.naming
.Name
;
25 import javax
.naming
.NamingException
;
26 import javax
.naming
.directory
.DirContext
;
28 import org
.argeo
.security
.UserAdminDao
;
29 import org
.springframework
.ldap
.core
.ContextExecutor
;
30 import org
.springframework
.ldap
.core
.ContextMapper
;
31 import org
.springframework
.ldap
.core
.DirContextAdapter
;
32 import org
.springframework
.ldap
.core
.DistinguishedName
;
33 import org
.springframework
.ldap
.core
.LdapTemplate
;
34 import org
.springframework
.ldap
.core
.support
.BaseLdapPathContextSource
;
35 import org
.springframework
.security
.ldap
.LdapUsernameToDnMapper
;
36 import org
.springframework
.security
.ldap
.LdapUtils
;
39 * Wraps a Spring LDAP user details manager, providing additional methods to
42 public class ArgeoSecurityDaoLdap
implements UserAdminDao
{
43 private String userBase
;
44 private String usernameAttribute
;
45 private String groupBase
;
46 private String
[] groupClasses
;
48 private String groupRoleAttribute
;
49 private String groupMemberAttribute
;
50 private String defaultRole
;
51 private String rolePrefix
;
53 private final LdapTemplate ldapTemplate
;
54 private LdapUsernameToDnMapper usernameMapper
;
57 * Standard constructor, using the LDAP context source shared with Spring
58 * Security components.
60 public ArgeoSecurityDaoLdap(BaseLdapPathContextSource contextSource
) {
61 this.ldapTemplate
= new LdapTemplate(contextSource
);
64 @SuppressWarnings("unchecked")
65 public synchronized Set
<String
> listUsers() {
66 List
<String
> usernames
= (List
<String
>) ldapTemplate
.listBindings(
67 new DistinguishedName(userBase
), new ContextMapper() {
68 public Object
mapFromContext(Object ctxArg
) {
69 DirContextAdapter ctx
= (DirContextAdapter
) ctxArg
;
70 return ctx
.getStringAttribute(usernameAttribute
);
75 .unmodifiableSortedSet(new TreeSet
<String
>(usernames
));
78 @SuppressWarnings("unchecked")
79 public Set
<String
> listEditableRoles() {
80 return Collections
.unmodifiableSortedSet(new TreeSet
<String
>(
81 ldapTemplate
.listBindings(groupBase
, new ContextMapper() {
82 public Object
mapFromContext(Object ctxArg
) {
83 String groupName
= ((DirContextAdapter
) ctxArg
)
84 .getStringAttribute(groupRoleAttribute
);
85 String roleName
= convertGroupToRole(groupName
);
91 @SuppressWarnings("unchecked")
92 public Set
<String
> listUsersInRole(String role
) {
93 return (Set
<String
>) ldapTemplate
.lookup(
94 buildGroupDn(convertRoleToGroup(role
)), new ContextMapper() {
95 public Object
mapFromContext(Object ctxArg
) {
96 DirContextAdapter ctx
= (DirContextAdapter
) ctxArg
;
97 String
[] userDns
= ctx
98 .getStringAttributes(groupMemberAttribute
);
99 TreeSet
<String
> set
= new TreeSet
<String
>();
100 for (String userDn
: userDns
) {
101 DistinguishedName dn
= new DistinguishedName(userDn
);
102 String username
= dn
.getValue(usernameAttribute
);
105 return Collections
.unmodifiableSortedSet(set
);
110 public void createRole(String role
, final String superuserName
) {
111 String group
= convertRoleToGroup(role
);
112 DistinguishedName superuserDn
= (DistinguishedName
) ldapTemplate
113 .executeReadWrite(new ContextExecutor() {
114 public Object
executeWithContext(DirContext ctx
)
115 throws NamingException
{
116 return LdapUtils
.getFullDn(
117 usernameMapper
.buildDn(superuserName
), ctx
);
121 Name groupDn
= buildGroupDn(group
);
122 DirContextAdapter context
= new DirContextAdapter();
123 context
.setAttributeValues("objectClass", groupClasses
);
124 context
.setAttributeValue("cn", group
);
125 // Add superuser because cannot create empty group
126 context
.setAttributeValue(groupMemberAttribute
, superuserDn
.toString());
127 ldapTemplate
.bind(groupDn
, context
, null);
130 public void deleteRole(String role
) {
131 String group
= convertRoleToGroup(role
);
132 Name dn
= buildGroupDn(group
);
133 ldapTemplate
.unbind(dn
);
136 /** Maps a role (ROLE_XXX) to the related LDAP group (xxx) */
137 protected String
convertRoleToGroup(String role
) {
139 if (group
.startsWith(rolePrefix
)) {
140 group
= group
.substring(rolePrefix
.length());
141 group
= group
.toLowerCase();
146 /** Maps anLDAP group (xxx) to the related role (ROLE_XXX) */
147 protected String
convertGroupToRole(String groupName
) {
148 groupName
= groupName
.toUpperCase();
150 return rolePrefix
+ groupName
;
153 protected Name
buildGroupDn(String name
) {
154 return new DistinguishedName(groupRoleAttribute
+ "=" + name
+ ","
158 public void setUserBase(String userBase
) {
159 this.userBase
= userBase
;
162 public void setUsernameAttribute(String usernameAttribute
) {
163 this.usernameAttribute
= usernameAttribute
;
166 public void setGroupBase(String groupBase
) {
167 this.groupBase
= groupBase
;
170 public void setGroupRoleAttribute(String groupRoleAttributeName
) {
171 this.groupRoleAttribute
= groupRoleAttributeName
;
174 public void setGroupMemberAttribute(String groupMemberAttributeName
) {
175 this.groupMemberAttribute
= groupMemberAttributeName
;
178 public void setDefaultRole(String defaultRole
) {
179 this.defaultRole
= defaultRole
;
182 public void setRolePrefix(String rolePrefix
) {
183 this.rolePrefix
= rolePrefix
;
186 public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper
) {
187 this.usernameMapper
= usernameMapper
;
190 public String
getDefaultRole() {
194 public void setGroupClasses(String
[] groupClasses
) {
195 this.groupClasses
= groupClasses
;