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