001/*
002 *   Licensed to the Apache Software Foundation (ASF) under one
003 *   or more contributor license agreements.  See the NOTICE file
004 *   distributed with this work for additional information
005 *   regarding copyright ownership.  The ASF licenses this file
006 *   to you under the Apache License, Version 2.0 (the
007 *   "License"); you may not use this file except in compliance
008 *   with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *   Unless required by applicable law or agreed to in writing,
013 *   software distributed under the License is distributed on an
014 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *   KIND, either express or implied.  See the License for the
016 *   specific language governing permissions and limitations
017 *   under the License.
018 *
019 */
020package org.apache.directory.server.core.authn;
021
022
023import java.net.SocketAddress;
024
025import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
026import org.apache.directory.api.ldap.model.entry.Entry;
027import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
028import org.apache.directory.api.ldap.model.exception.LdapException;
029import org.apache.directory.api.ldap.model.name.Dn;
030import org.apache.directory.api.util.Strings;
031import org.apache.directory.ldap.client.api.LdapConnectionConfig;
032import org.apache.directory.ldap.client.api.LdapNetworkConnection;
033import org.apache.directory.ldap.client.api.NoVerificationTrustManager;
034import org.apache.directory.server.core.api.LdapPrincipal;
035import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
036import org.apache.directory.server.i18n.I18n;
037import org.apache.mina.core.session.IoSession;
038
039
040/**
041 * Authenticator delegating to another LDAP server.
042 *
043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044 */
045public class DelegatingAuthenticator extends AbstractAuthenticator
046{
047    /** A speedup for logger in debug mode */
048    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
049
050    /** The host in charge of delegated authentication */
051    private String delegateHost;
052
053    /** The associated port */
054    private int delegatePort;
055
056    /** Tells if we use SSL to connect */
057    private boolean delegateSsl;
058
059    /** Tells if we use StartTLS to connect */
060    private boolean delegateTls;
061
062    /** The SSL TrustManager FQCN to use */
063    private String delegateSslTrustManagerFQCN;
064
065    /** The startTLS TrustManager FQCN to use */
066    private String delegateTlsTrustManagerFQCN;
067
068
069    /**
070     * Creates a new instance.
071     */
072    public DelegatingAuthenticator()
073    {
074        super( AuthenticationLevel.SIMPLE );
075    }
076
077
078    /**
079     * Creates a new instance.
080     * @see AbstractAuthenticator
081     * @param baseDn The base Dn
082     */
083    public DelegatingAuthenticator( Dn baseDn )
084    {
085        super( AuthenticationLevel.SIMPLE, baseDn );
086    }
087
088
089    /**
090     * Creates a new instance, for a specific authentication level.
091     * @see AbstractAuthenticator
092     * @param type The relevant AuthenticationLevel
093     * @param baseDn The base Dn
094     */
095    protected DelegatingAuthenticator( AuthenticationLevel type, Dn baseDn )
096    {
097        super( type, baseDn );
098    }
099
100
101    /**
102     * @return the delegateHost
103     */
104    public String getDelegateHost()
105    {
106        return delegateHost;
107    }
108
109
110    /**
111     * @param delegateHost the delegateHost to set
112     */
113    public void setDelegateHost( String delegateHost )
114    {
115        this.delegateHost = delegateHost;
116    }
117
118
119    /**
120     * @return the delegatePort
121     */
122    public int getDelegatePort()
123    {
124        return delegatePort;
125    }
126
127
128    /**
129     * @param delegatePort the delegatePort to set
130     */
131    public void setDelegatePort( int delegatePort )
132    {
133        this.delegatePort = delegatePort;
134    }
135
136
137    /**
138     * @return the delegateSsl
139     */
140    public boolean isDelegateSsl()
141    {
142        return delegateSsl;
143    }
144
145
146    /**
147     * @param delegateSsl the delegateSsl to set
148     */
149    public void setDelegateSsl( boolean delegateSsl )
150    {
151        this.delegateSsl = delegateSsl;
152    }
153
154
155    /**
156     * @return the delegateBaseDn
157     */
158    public String getDelegateBaseDn()
159    {
160        return getBaseDn().toString();
161    }
162
163
164    /**
165     * @return the delegateTls
166     */
167    public boolean isDelegateTls()
168    {
169        return delegateTls;
170    }
171
172
173    /**
174     * @param delegateTls the delegateTls to set
175     */
176    public void setDelegateTls( boolean delegateTls )
177    {
178        this.delegateTls = delegateTls;
179    }
180
181
182    /**
183     * @return the delegateSslTrustManagerFQCN
184     */
185    public String getDelegateSslTrustManagerFQCN()
186    {
187        return delegateSslTrustManagerFQCN;
188    }
189
190
191    /**
192     * @param delegateSslTrustManagerFQCN the delegateSslTrustManagerFQCN to set
193     */
194    public void setDelegateSslTrustManagerFQCN( String delegateSslTrustManagerFQCN )
195    {
196        this.delegateSslTrustManagerFQCN = delegateSslTrustManagerFQCN;
197    }
198
199
200    /**
201     * @return the delegateTlsTrustManagerFQCN
202     */
203    public String getDelegateTlsTrustManagerFQCN()
204    {
205        return delegateTlsTrustManagerFQCN;
206    }
207
208
209    /**
210     * @param delegateTlsTrustManagerFQCN the delegateTlsTrustManagerFQCN to set
211     */
212    public void setDelegateTlsTrustManagerFQCN( String delegateTlsTrustManagerFQCN )
213    {
214        this.delegateTlsTrustManagerFQCN = delegateTlsTrustManagerFQCN;
215    }
216
217
218    /**
219     * {@inheritDoc}
220     */
221    @Override
222    public LdapPrincipal authenticate( BindOperationContext bindContext )
223        throws LdapException
224    {
225        LdapPrincipal principal = null;
226
227        if ( IS_DEBUG )
228        {
229            LOG.debug( "Authenticating {}", bindContext.getDn() );
230        }
231
232        // First, check that the Bind DN is under the delegateBaseDn
233        Dn bindDn = bindContext.getDn();
234
235        // Don't authenticate using this authenticator if the Bind ND is not a descendant of the
236        // configured delegate base DN (or if it's null)
237        if ( ( getBaseDn() == null ) || ( !bindDn.isDescendantOf( getBaseDn() ) ) )
238        {
239            return null;
240        }
241
242        LdapConnectionConfig connectionConfig;
243        LdapNetworkConnection ldapConnection;
244
245        // Create a connection on the remote host
246        if ( delegateTls )
247        {
248            connectionConfig = new LdapConnectionConfig();
249            connectionConfig.setLdapHost( delegateHost );
250            connectionConfig.setLdapPort( delegatePort );
251            connectionConfig.setTrustManagers( new NoVerificationTrustManager() );
252
253            ldapConnection = new LdapNetworkConnection( connectionConfig );
254            ldapConnection.connect();
255            ldapConnection.startTls();
256        }
257        else if ( delegateSsl )
258        {
259            connectionConfig = new LdapConnectionConfig();
260            connectionConfig.setLdapHost( delegateHost );
261            connectionConfig.setUseSsl( true );
262            connectionConfig.setLdapPort( delegatePort );
263            connectionConfig.setTrustManagers( new NoVerificationTrustManager() );
264
265            ldapConnection = new LdapNetworkConnection( connectionConfig );
266            ldapConnection.connect();
267        }
268        else
269        {
270            connectionConfig = new LdapConnectionConfig();
271            connectionConfig.setLdapHost( delegateHost );
272            connectionConfig.setLdapPort( delegatePort );
273
274            ldapConnection = new LdapNetworkConnection( delegateHost, delegatePort );
275            ldapConnection.connect();
276        }
277
278        ldapConnection.setTimeOut( 0L );
279
280        try
281        {
282            // Try to bind
283            try
284            {
285                ldapConnection.bind( bindDn, Strings.utf8ToString( bindContext.getCredentials() ) );
286            }
287            catch ( LdapException le )
288            {
289                String message = I18n.err( I18n.ERR_230, bindDn.getName() );
290                LOG.info( message );
291                throw new LdapAuthenticationException( message );
292            }
293            finally
294            {
295                // no need to remain bound to delegate host
296                ldapConnection.unBind();
297
298                if ( IS_DEBUG )
299                {
300                    LOG.debug( "Authenticated successfully {}", bindContext.getDn() );
301                }
302            }
303
304            // Create the new principal
305            principal = new LdapPrincipal( getDirectoryService().getSchemaManager(), bindDn,
306                AuthenticationLevel.SIMPLE,
307                bindContext.getCredentials() );
308
309            IoSession session = bindContext.getIoSession();
310
311            if ( session != null )
312            {
313                SocketAddress clientAddress = session.getRemoteAddress();
314                principal.setClientAddress( clientAddress );
315                SocketAddress serverAddress = session.getServiceAddress();
316                principal.setServerAddress( serverAddress );
317            }
318
319            return principal;
320        }
321        catch ( LdapException e )
322        {
323            // Bad password ...
324            String message = I18n.err( I18n.ERR_230, bindDn.getName() );
325            LOG.info( message );
326            throw new LdapAuthenticationException( message );
327        }
328        finally
329        {
330            ldapConnection.close();
331        }
332    }
333
334
335    /**
336     * We don't handle any password policy when using a delegated authentication
337     */
338    @Override
339    public void checkPwdPolicy( Entry userEntry ) throws LdapException
340    {
341        // no check for delegating authentication
342    }
343
344
345    /**
346     * We don't handle any cache when using a delegated authentication
347     */
348    @Override
349    public void invalidateCache( Dn bindDn )
350    {
351        // cache is not implemented here
352    }
353}