View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.server.ldap.handlers.sasl.gssapi;
21  
22  
23  import java.security.PrivilegedExceptionAction;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import javax.security.auth.Subject;
28  import javax.security.auth.callback.CallbackHandler;
29  import javax.security.auth.kerberos.KerberosKey;
30  import javax.security.auth.kerberos.KerberosPrincipal;
31  import javax.security.sasl.Sasl;
32  import javax.security.sasl.SaslServer;
33  
34  import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms;
35  import org.apache.directory.api.ldap.model.message.BindRequest;
36  import org.apache.directory.api.ldap.model.name.Dn;
37  import org.apache.directory.server.core.api.CoreSession;
38  import org.apache.directory.server.i18n.I18n;
39  import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
40  import org.apache.directory.server.protocol.shared.kerberos.GetPrincipal;
41  import org.apache.directory.server.ldap.LdapServer;
42  import org.apache.directory.server.ldap.LdapSession;
43  import org.apache.directory.server.ldap.handlers.sasl.AbstractMechanismHandler;
44  import org.apache.directory.server.ldap.handlers.sasl.SaslConstants;
45  import org.apache.directory.server.protocol.shared.ServiceConfigurationException;
46  import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
47  import org.apache.directory.shared.kerberos.components.EncryptionKey;
48  
49  
50  /**
51   * The GSSAPI Sasl mechanism handler.
52   *
53   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
54   */
55  public class GssapiMechanismHandler extends AbstractMechanismHandler
56  {
57      public SaslServer handleMechanism( LdapSession ldapSession, BindRequest bindRequest ) throws Exception
58      {
59          SaslServer ss = ( SaslServer ) ldapSession.getSaslProperty( SaslConstants.SASL_SERVER );
60  
61          if ( ss == null )
62          {
63              Subject subject = getSubject( ldapSession.getLdapServer() );
64              final String saslHost = ( String ) ldapSession.getSaslProperty( SaslConstants.SASL_HOST );
65              final Map<String, String> saslProps = ( Map<String, String> ) ldapSession
66                  .getSaslProperty( SaslConstants.SASL_PROPS );
67  
68              CoreSession adminSession = ldapSession.getLdapServer().getDirectoryService().getAdminSession();
69  
70              final CallbackHandler callbackHandler = new GssapiCallbackHandler( ldapSession, adminSession, bindRequest );
71  
72              ss = Subject.doAs( subject, new PrivilegedExceptionAction<SaslServer>()
73              {
74                  public SaslServer run() throws Exception
75                  {
76                      return Sasl.createSaslServer( SupportedSaslMechanisms.GSSAPI, SaslConstants.LDAP_PROTOCOL,
77                          saslHost, saslProps, callbackHandler );
78                  }
79              } );
80  
81              ldapSession.putSaslProperty( SaslConstants.SASL_SERVER, ss );
82          }
83  
84          return ss;
85      }
86  
87  
88      /**
89       * {@inheritDoc}
90       */
91      public void init( LdapSession ldapSession )
92      {
93          // Store the host in the ldap session
94          String saslHost = ldapSession.getLdapServer().getSaslHost();
95          ldapSession.putSaslProperty( SaslConstants.SASL_HOST, saslHost );
96  
97          Map<String, String> saslProps = new HashMap<>();
98          saslProps.put( Sasl.QOP, ldapSession.getLdapServer().getSaslQopString() );
99          ldapSession.putSaslProperty( SaslConstants.SASL_PROPS, saslProps );
100     }
101 
102 
103     /**
104      * Remove the Host, UserBaseDn, props and Mechanism property.
105      * 
106      * @param ldapSession the Ldapsession instance
107      */
108     public void cleanup( LdapSession ldapSession )
109     {
110         // Inject the Sasl Filter
111         insertSaslFilter( ldapSession );
112 
113         // and remove the useless informations
114         ldapSession.removeSaslProperty( SaslConstants.SASL_HOST );
115         ldapSession.removeSaslProperty( SaslConstants.SASL_USER_BASE_DN );
116         ldapSession.removeSaslProperty( SaslConstants.SASL_MECH );
117         ldapSession.removeSaslProperty( SaslConstants.SASL_PROPS );
118         ldapSession.removeSaslProperty( SaslConstants.SASL_AUTHENT_USER );
119     }
120 
121 
122     private Subject getSubject( LdapServer ldapServer ) throws Exception
123     {
124         String servicePrincipalName = ldapServer.getSaslPrincipal();
125         KerberosPrincipal servicePrincipal = new KerberosPrincipal( servicePrincipalName );
126         GetPrincipalprotocol/shared/kerberos/GetPrincipal.html#GetPrincipal">GetPrincipal getPrincipal = new GetPrincipal( servicePrincipal );
127 
128         PrincipalStoreEntry entry = null;
129 
130         try
131         {
132             entry = findPrincipal( ldapServer, getPrincipal );
133         }
134         catch ( ServiceConfigurationException sce )
135         {
136             String message = I18n.err( I18n.ERR_659, servicePrincipalName, ldapServer.getSearchBaseDn() );
137             throw new ServiceConfigurationException( message, sce );
138         }
139 
140         if ( entry == null )
141         {
142             String message = I18n.err( I18n.ERR_659, servicePrincipalName, ldapServer.getSearchBaseDn() );
143             throw new ServiceConfigurationException( message );
144         }
145 
146         Subject subject = new Subject();
147 
148         for ( EncryptionType encryptionType : entry.getKeyMap().keySet() )
149         {
150             EncryptionKey key = entry.getKeyMap().get( encryptionType );
151 
152             byte[] keyBytes = key.getKeyValue();
153             int type = key.getKeyType().getValue();
154             int kvno = key.getKeyVersion();
155 
156             KerberosKey serviceKey = new KerberosKey( servicePrincipal, keyBytes, type, kvno );
157 
158             subject.getPrivateCredentials().add( serviceKey );
159         }
160 
161         return subject;
162     }
163 
164 
165     private PrincipalStoreEntry findPrincipal( LdapServer ldapServer, GetPrincipal getPrincipal ) throws Exception
166     {
167         CoreSession adminSession = ldapServer.getDirectoryService().getAdminSession();
168         return ( PrincipalStoreEntry ) getPrincipal.execute( adminSession, new Dn( ldapServer.getSearchBaseDn() ) );
169     }
170 }