1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/**
* $RCSfile$
* $Revision: $
* $Date: 2006-04-07 09:28:54 -0500 (Fri, 07 Apr 2006) $
*
* Copyright (C) 2004-2008 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.openfire.ldap;
import javax.naming.NamingEnumeration;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.jivesoftware.openfire.auth.AuthorizationMapping;
import org.jivesoftware.util.JiveGlobals;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Provider for authorization mapping using LDAP. If the authenticated
* principal did not request a username, provide one via LDAP. Specify the
* lookup field in the system properties. An entry in that file would
* look like the following:
*
* <ul>
* <li><tt>ldap.princField = k5login</tt></li>
* <li><tt>ldap.princSearchFilter = princField={0}</tt></li>
* </ul>
* <p/>
* Each ldap object that represents a user is expcted to have exactly one of
* ldap.usernameField and ldap.princField, and they are both expected to be unique
* over the search base. A search will be performed over all objects where
* princField = principal, and the usernameField will be returned.
* Note that it is expected this search return exactly one object. (There can
* only be one default) If more than one is returned, the first entry
* encountered will be used, and no sorting is performed or requested.
* If more control over the search is needed, you can specify the mapSearchFilter
* used to perform the LDAP query.
* This implementation requires that LDAP be configured, obviously.
*
*
* @author Jay Kline
*/
public class LdapAuthorizationMapping implements AuthorizationMapping {
private static final Logger Log = LoggerFactory.getLogger(LdapAuthorizationMapping.class);
private LdapManager manager;
private String usernameField;
private String princField;
private String princSearchFilter;
public LdapAuthorizationMapping() {
// Convert XML based provider setup to Database based
JiveGlobals.migrateProperty("ldap.princField");
JiveGlobals.migrateProperty("ldap.princSearchFilter");
manager = LdapManager.getInstance();
usernameField = manager.getUsernameField();
princField = JiveGlobals.getProperty("ldap.princField", "k5login");
princSearchFilter = JiveGlobals.getProperty("ldap.princSearchFilter");
StringBuilder filter = new StringBuilder();
if(princSearchFilter == null) {
filter.append("(").append(princField).append("={0})");
} else {
filter.append("(&(").append(princField).append("={0})(");
filter.append(princSearchFilter).append("))");
}
princSearchFilter = filter.toString();
}
public String map(String principal) {
String username = principal;
DirContext ctx = null;
try {
Log.debug("LdapAuthorizationMapping: Starting LDAP search...");
String usernameField = manager.getUsernameField();
//String baseDN = manager.getBaseDN();
boolean subTreeSearch = manager.isSubTreeSearch();
ctx = manager.getContext();
SearchControls constraints = new SearchControls();
if (subTreeSearch) {
constraints.setSearchScope
(SearchControls.SUBTREE_SCOPE);
}
// Otherwise, only search a single level.
else {
constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE);
}
constraints.setReturningAttributes(new String[] { usernameField });
NamingEnumeration answer = ctx.search("", princSearchFilter, new String[] {principal},
constraints);
Log.debug("LdapAuthorizationMapping: ... search finished");
if (answer == null || !answer.hasMoreElements()) {
Log.debug("LdapAuthorizationMapping: Username based on principal '" + principal + "' not found.");
return principal;
}
Attributes atrs = ((SearchResult)answer.next()).getAttributes();
Attribute usernameAttribute = atrs.get(usernameField);
username = (String) usernameAttribute.get();
}
catch (Exception e) {
// Ignore.
}
finally {
try {
if (ctx != null) {
ctx.close();
}
}
catch (Exception ignored) {
// Ignore.
}
}
return username;
}
/**
* Returns the short name of the Policy
*
* @return The short name of the Policy
*/
public String name() {
return "LDAP Authorization Mapping";
}
/**
* Returns a description of the Policy
*
* @return The description of the Policy.
*/
public String description() {
return "Provider for authorization using LDAP. Returns the principals default username using the attribute specified in ldap.princField.";
}
}