1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.ldap.handlers.sasl.plain;
21
22
23 import java.io.IOException;
24
25 import javax.naming.InvalidNameException;
26 import javax.security.sasl.SaslException;
27
28 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
29 import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
30 import org.apache.directory.api.ldap.model.entry.Entry;
31 import org.apache.directory.api.ldap.model.entry.Value;
32 import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
33 import org.apache.directory.api.ldap.model.filter.EqualityNode;
34 import org.apache.directory.api.ldap.model.message.BindRequest;
35 import org.apache.directory.api.ldap.model.message.SearchScope;
36 import org.apache.directory.api.ldap.model.schema.PrepareString;
37 import org.apache.directory.api.util.Strings;
38 import org.apache.directory.server.core.api.CoreSession;
39 import org.apache.directory.server.core.api.DirectoryService;
40 import org.apache.directory.server.core.api.OperationEnum;
41 import org.apache.directory.server.core.api.OperationManager;
42 import org.apache.directory.server.core.api.filtering.EntryFilteringCursor;
43 import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
44 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
45 import org.apache.directory.server.i18n.I18n;
46 import org.apache.directory.server.ldap.LdapServer;
47 import org.apache.directory.server.ldap.LdapSession;
48 import org.apache.directory.server.ldap.handlers.sasl.AbstractSaslServer;
49
50
51
52
53
54
55
56
57
58 public final class PlainSaslServer extends AbstractSaslServer
59 {
60
61 public static final String SASL_PLAIN_AUTHZID = "authzid";
62
63
64 public static final String SASL_PLAIN_AUTHCID = "authcid";
65
66
67 public static final String SASL_PLAIN_PASSWORD = "password";
68
69
70
71
72 private enum NegotiationState
73 {
74 INITIALIZED,
75 MECH_RECEIVED,
76 COMPLETED
77 }
78
79
80
81
82 private enum InitialResponse
83 {
84 AUTHZID_EXPECTED,
85 AUTHCID_EXPECTED,
86 PASSWORD_EXPECTED
87 }
88
89
90 private NegotiationState state;
91
92
93
94
95
96
97
98
99
100 public PlainSaslServer( LdapSession ldapSession, CoreSession adminSession, BindRequest bindRequest )
101 {
102 super( ldapSession, adminSession, bindRequest );
103 state = NegotiationState.INITIALIZED;
104
105
106 getLdapSession().removeSaslProperty( SASL_PLAIN_AUTHZID );
107 getLdapSession().removeSaslProperty( SASL_PLAIN_AUTHCID );
108 getLdapSession().removeSaslProperty( SASL_PLAIN_PASSWORD );
109 }
110
111
112
113
114
115 public String getMechanismName()
116 {
117 return SupportedSaslMechanisms.PLAIN;
118 }
119
120
121
122
123
124 public byte[] evaluateResponse( byte[] initialResponse ) throws SaslException
125 {
126 if ( Strings.isEmpty( initialResponse ) )
127 {
128 state = NegotiationState.MECH_RECEIVED;
129 return null;
130 }
131 else
132 {
133
134
135
136
137
138
139
140
141
142 InitialResponse element = InitialResponse.AUTHZID_EXPECTED;
143 String authzId = null;
144 String authcId = null;
145 String password = null;
146
147 int start = 0;
148 int end = 0;
149
150 try
151 {
152 for ( byte b : initialResponse )
153 {
154 if ( b == '\0' )
155 {
156 if ( start - end == 0 )
157 {
158
159 if ( element == InitialResponse.AUTHZID_EXPECTED )
160 {
161
162
163 element = InitialResponse.AUTHCID_EXPECTED;
164 }
165 else
166 {
167
168 throw new IllegalArgumentException( I18n.err( I18n.ERR_671 ) );
169 }
170 }
171 else
172 {
173 start++;
174 String value = new String( initialResponse, start, end - start + 1, "UTF-8" );
175
176 switch ( element )
177 {
178 case AUTHZID_EXPECTED:
179 element = InitialResponse.AUTHCID_EXPECTED;
180 authzId = PrepareString.normalize( value );
181 end++;
182 start = end;
183 break;
184
185 case AUTHCID_EXPECTED:
186 element = InitialResponse.PASSWORD_EXPECTED;
187 authcId = PrepareString
188 .normalize( value );
189 end++;
190 start = end;
191 break;
192
193 default:
194
195 throw new IllegalArgumentException( I18n.err( I18n.ERR_672 ) );
196 }
197 }
198 }
199 else
200 {
201 end++;
202 }
203 }
204
205 if ( start == end )
206 {
207 throw new IllegalArgumentException( I18n.err( I18n.ERR_671 ) );
208 }
209
210 start++;
211 String value = Strings.utf8ToString( initialResponse, start, end - start + 1 );
212
213 password = PrepareString.normalize( value );
214
215 if ( ( authcId == null ) || ( password == null ) )
216 {
217 throw new IllegalArgumentException( I18n.err( I18n.ERR_671 ) );
218 }
219
220
221 CoreSession userSession = authenticate( authcId, password );
222
223 getLdapSession().setCoreSession( userSession );
224
225 state = NegotiationState.COMPLETED;
226 }
227 catch ( IOException ioe )
228 {
229 throw new IllegalArgumentException( I18n.err( I18n.ERR_674 ) );
230 }
231 catch ( InvalidNameException ine )
232 {
233 throw new IllegalArgumentException( I18n.err( I18n.ERR_675 ) );
234 }
235 catch ( Exception e )
236 {
237 throw new SaslException( I18n.err( I18n.ERR_676, authcId ) );
238 }
239 }
240
241 return Strings.EMPTY_BYTES;
242 }
243
244
245 public boolean isComplete()
246 {
247 return state == NegotiationState.COMPLETED;
248 }
249
250
251
252
253
254
255 private CoreSession authenticate( String user, String password ) throws Exception
256 {
257 LdapSession ldapSession = getLdapSession();
258 CoreSession adminSession = getAdminSession();
259 DirectoryService directoryService = adminSession.getDirectoryService();
260 LdapServer ldapServer = ldapSession.getLdapServer();
261 OperationManager operationManager = directoryService.getOperationManager();
262
263
264 EqualityNode<String> filter = new EqualityNode<>(
265 directoryService.getSchemaManager().getAttributeType( SchemaConstants.UID_AT ), new Value( user ) );
266
267 SearchOperationContextterceptor/context/SearchOperationContext.html#SearchOperationContext">SearchOperationContext searchContext = new SearchOperationContext( directoryService.getAdminSession() );
268 searchContext.setDn( directoryService.getDnFactory().create( ldapServer.getSearchBaseDn() ) );
269 searchContext.setScope( SearchScope.SUBTREE );
270 searchContext.setFilter( filter );
271 searchContext.setNoAttributes( true );
272
273 EntryFilteringCursor cursor = operationManager.search( searchContext );
274 Exception bindException = new LdapAuthenticationException( "Cannot authenticate user uid=" + user );
275
276 while ( cursor.next() )
277 {
278 Entry entry = cursor.get();
279
280 try
281 {
282 BindOperationContexti/interceptor/context/BindOperationContext.html#BindOperationContext">BindOperationContext bindContext = new BindOperationContext( ldapSession.getCoreSession() );
283 bindContext.setDn( entry.getDn() );
284 bindContext.setCredentials( Strings.getBytesUtf8( password ) );
285 bindContext.setIoSession( ldapSession.getIoSession() );
286 bindContext.setInterceptors( directoryService.getInterceptors( OperationEnum.BIND ) );
287
288 operationManager.bind( bindContext );
289
290 cursor.close();
291
292 return bindContext.getSession();
293 }
294 catch ( Exception e )
295 {
296 bindException = e;
297 }
298 }
299
300 cursor.close();
301
302 throw bindException;
303 }
304 }