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;
21
22
23 import java.util.Hashtable;
24
25 import javax.naming.Context;
26 import javax.naming.ldap.InitialLdapContext;
27 import javax.naming.ldap.LdapContext;
28 import javax.security.auth.callback.Callback;
29 import javax.security.auth.callback.CallbackHandler;
30 import javax.security.auth.callback.NameCallback;
31 import javax.security.auth.callback.PasswordCallback;
32 import javax.security.sasl.AuthorizeCallback;
33 import javax.security.sasl.RealmCallback;
34
35 import org.apache.commons.lang3.exception.ExceptionUtils;
36 import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
37 import org.apache.directory.api.ldap.model.entry.Attribute;
38 import org.apache.directory.api.ldap.model.exception.LdapOperationException;
39 import org.apache.directory.api.ldap.model.message.BindRequest;
40 import org.apache.directory.api.ldap.model.message.Control;
41 import org.apache.directory.api.ldap.model.message.LdapResult;
42 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
43 import org.apache.directory.api.ldap.model.name.Dn;
44 import org.apache.directory.api.ldap.util.JndiUtils;
45 import org.apache.directory.api.util.Strings;
46 import org.apache.directory.server.constants.ServerDNConstants;
47 import org.apache.directory.server.core.api.CoreSession;
48 import org.apache.directory.server.core.api.DirectoryService;
49 import org.apache.directory.server.i18n.I18n;
50 import org.apache.directory.server.ldap.LdapSession;
51 import org.apache.mina.core.session.IoSession;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55
56
57
58
59
60
61
62
63 public abstract class AbstractSaslCallbackHandler implements CallbackHandler
64 {
65
66 private static final Logger LOG = LoggerFactory.getLogger( AbstractSaslCallbackHandler.class );
67
68
69 private static final Control[] EMPTY = new Control[0];
70
71 private String username;
72 private String realm;
73
74
75 protected LdapSession ldapSession;
76
77
78 protected CoreSession adminSession;
79
80
81 protected final DirectoryService directoryService;
82
83
84 protected final BindRequest bindRequest;
85
86
87
88
89
90
91
92
93 protected AbstractSaslCallbackHandler( DirectoryService directoryService, BindRequest bindRequest )
94 {
95 this.directoryService = directoryService;
96 this.bindRequest = bindRequest;
97 }
98
99
100
101
102
103
104
105
106
107 protected String getUsername()
108 {
109 return username;
110 }
111
112
113
114
115
116
117
118
119
120 protected String getRealm()
121 {
122 return realm;
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 protected abstract Attribute lookupPassword( String username, String realm );
139
140
141
142
143
144
145
146
147
148
149
150
151 protected abstract void authorize( AuthorizeCallback callback ) throws Exception;
152
153
154
155
156
157
158
159
160 @Override
161 public void handle( Callback[] callbacks )
162 {
163 for ( int i = 0; i < callbacks.length; i++ )
164 {
165 Callback callback = callbacks[i];
166
167 if ( LOG.isDebugEnabled() )
168 {
169 LOG.debug( "Processing callback {} of {}: {}", callback.getClass(), ( i + 1 ), callbacks.length );
170 }
171
172 if ( callback instanceof NameCallback )
173 {
174 NameCallback nameCB = ( NameCallback ) callback;
175 LOG.debug( "NameCallback default name: {}", nameCB.getDefaultName() );
176
177 username = nameCB.getDefaultName();
178 }
179 else if ( callback instanceof RealmCallback )
180 {
181 RealmCallback realmCB = ( RealmCallback ) callback;
182 LOG.debug( "RealmCallback default text: {}", realmCB.getDefaultText() );
183
184 realm = realmCB.getDefaultText();
185 }
186 else if ( callback instanceof PasswordCallback )
187 {
188 PasswordCallback passwordCB = ( PasswordCallback ) callback;
189 Attribute userPassword = lookupPassword( getUsername(), getRealm() );
190
191 if ( userPassword != null )
192 {
193
194 byte[] password = userPassword.get().getBytes();
195
196 String strPassword = Strings.utf8ToString( password );
197 passwordCB.setPassword( strPassword.toCharArray() );
198 }
199 }
200 else if ( callback instanceof AuthorizeCallback )
201 {
202 AuthorizeCallback authorizeCB = ( AuthorizeCallback ) callback;
203
204
205
206 LOG.debug( "AuthorizeCallback authnID: {}", authorizeCB.getAuthenticationID() );
207
208
209
210 LOG.debug( "AuthorizeCallback authzID: {}", authorizeCB.getAuthorizationID() );
211
212
213 LOG.debug( "AuthorizeCallback authorizedID: {}", authorizeCB.getAuthorizedID() );
214
215
216 LOG.debug( "AuthorizeCallback isAuthorized: {}", authorizeCB.isAuthorized() );
217
218 try
219 {
220 authorize( authorizeCB );
221 }
222 catch ( Exception e )
223 {
224
225 throw new RuntimeException( I18n.err( I18n.ERR_677 ), e );
226 }
227 }
228 }
229 }
230
231
232
233
234
235
236
237
238
239
240
241 protected LdapContext getContext( IoSession session, BindRequest bindRequest, Hashtable<String, Object> env )
242 {
243 LdapResult result = bindRequest.getResultResponse().getLdapResult();
244
245 LdapContext ctx = null;
246
247 try
248 {
249 Control[] connCtls = bindRequest.getControls().values().toArray( EMPTY );
250 env.put( DirectoryService.JNDI_KEY, directoryService );
251 ctx = new InitialLdapContext( env, JndiUtils.toJndiControls( directoryService.getLdapCodecService(),
252 connCtls ) );
253 }
254 catch ( Exception e )
255 {
256 ResultCodeEnum code;
257 Dn dn = null;
258
259 if ( e instanceof LdapOperationException )
260 {
261 code = ( ( LdapOperationException ) e ).getResultCode();
262 result.setResultCode( code );
263 dn = ( ( LdapOperationException ) e ).getResolvedDn();
264 }
265 else
266 {
267 code = ResultCodeEnum.getBestEstimate( e, bindRequest.getType() );
268 result.setResultCode( code );
269 }
270
271 String msg = "Bind failed: " + e.getLocalizedMessage();
272
273 if ( LOG.isDebugEnabled() )
274 {
275 msg += ":\n" + ExceptionUtils.getStackTrace( e );
276 msg += "\n\nBindRequest = \n" + bindRequest.toString();
277 }
278
279 if ( ( dn != null )
280 && ( ( code == ResultCodeEnum.NO_SUCH_OBJECT ) || ( code == ResultCodeEnum.ALIAS_PROBLEM )
281 || ( code == ResultCodeEnum.INVALID_DN_SYNTAX ) || ( code == ResultCodeEnum.ALIAS_DEREFERENCING_PROBLEM ) ) )
282 {
283 result.setMatchedDn( dn );
284 }
285
286 result.setDiagnosticMessage( msg );
287 session.write( bindRequest.getResultResponse() );
288 ctx = null;
289 }
290
291 return ctx;
292 }
293
294
295
296
297
298
299
300
301
302 protected Hashtable<String, Object> getEnvironment( IoSession session )
303 {
304 Hashtable<String, Object> env = new Hashtable<>();
305 env.put( Context.PROVIDER_URL, session.getAttribute( "baseDn" ) );
306 env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.directory.server.core.jndi.CoreContextFactory" );
307 env.put( Context.SECURITY_PRINCIPAL, ServerDNConstants.ADMIN_SYSTEM_DN );
308 env.put( Context.SECURITY_CREDENTIALS, "secret" );
309 env.put( Context.SECURITY_AUTHENTICATION, AuthenticationLevel.SIMPLE.toString() );
310
311 return env;
312 }
313 }