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 */
020 package org.apache.directory.server.ldap.handlers.bind.gssapi;
021
022
023 import java.security.PrivilegedExceptionAction;
024 import java.util.HashMap;
025 import java.util.Map;
026
027 import javax.security.auth.Subject;
028 import javax.security.auth.callback.CallbackHandler;
029 import javax.security.auth.kerberos.KerberosKey;
030 import javax.security.auth.kerberos.KerberosPrincipal;
031 import javax.security.sasl.Sasl;
032 import javax.security.sasl.SaslServer;
033
034 import org.apache.directory.server.core.CoreSession;
035 import org.apache.directory.server.kerberos.shared.crypto.encryption.EncryptionType;
036 import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
037 import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
038 import org.apache.directory.server.kerberos.shared.store.operations.GetPrincipal;
039 import org.apache.directory.server.ldap.LdapServer;
040 import org.apache.directory.server.ldap.LdapSession;
041 import org.apache.directory.server.ldap.handlers.bind.AbstractMechanismHandler;
042 import org.apache.directory.server.ldap.handlers.bind.SaslConstants;
043 import org.apache.directory.server.protocol.shared.ServiceConfigurationException;
044 import org.apache.directory.shared.ldap.constants.SupportedSaslMechanisms;
045 import org.apache.directory.shared.ldap.message.InternalBindRequest;
046 import org.apache.directory.shared.ldap.name.LdapDN;
047
048
049 /**
050 * The GSSAPI Sasl mechanism handler.
051 *
052 * @org.apache.xbean.XBean
053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
054 * @version $Rev$, $Date$
055 */
056 public class GssapiMechanismHandler extends AbstractMechanismHandler
057 {
058 public SaslServer handleMechanism( LdapSession ldapSession, InternalBindRequest bindRequest ) throws Exception
059 {
060 SaslServer ss = ( SaslServer ) ldapSession.getSaslProperty( SaslConstants.SASL_SERVER );
061
062 if ( ss == null )
063 {
064 //Subject subject = ( Subject ) ldapSession.getIoSession().getAttribute( "saslSubject" );
065
066 Subject subject = getSubject( ldapSession.getLdapServer() );
067 final String saslHost = ( String ) ldapSession.getSaslProperty( SaslConstants.SASL_HOST );
068 final Map<String, String> saslProps = ( Map<String, String> ) ldapSession
069 .getSaslProperty( SaslConstants.SASL_PROPS );
070
071 CoreSession adminSession = ldapSession.getLdapServer().getDirectoryService().getAdminSession();
072
073 final CallbackHandler callbackHandler = new GssapiCallbackHandler( ldapSession, adminSession, bindRequest );
074
075 ss = ( SaslServer ) Subject.doAs( subject, new PrivilegedExceptionAction<SaslServer>()
076 {
077 public SaslServer run() throws Exception
078 {
079 return Sasl.createSaslServer( SupportedSaslMechanisms.GSSAPI, SaslConstants.LDAP_PROTOCOL,
080 saslHost, saslProps, callbackHandler );
081 }
082 } );
083
084 ldapSession.putSaslProperty( SaslConstants.SASL_SERVER, ss );
085 }
086
087 return ss;
088 }
089
090
091 /**
092 * {@inheritDoc}
093 */
094 public void init( LdapSession ldapSession )
095 {
096 // Store the host in the ldap session
097 String saslHost = ldapSession.getLdapServer().getSaslHost();
098 ldapSession.putSaslProperty( SaslConstants.SASL_HOST, saslHost );
099
100 Map<String, String> saslProps = new HashMap<String, String>();
101 saslProps.put( Sasl.QOP, ldapSession.getLdapServer().getSaslQopString() );
102 //saslProps.put( "com.sun.security.sasl.digest.realm", getActiveRealms( ldapSession.getLdapServer() ) );
103 ldapSession.putSaslProperty( SaslConstants.SASL_PROPS, saslProps );
104 }
105
106
107 /**
108 * Remove the Host, UserBaseDn, props and Mechanism property.
109 *
110 * @param ldapSession the Ldapsession instance
111 */
112 public void cleanup( LdapSession ldapSession )
113 {
114 // Inject the Sasl Filter
115 insertSaslFilter( ldapSession );
116
117 // and remove the useless informations
118 ldapSession.removeSaslProperty( SaslConstants.SASL_HOST );
119 ldapSession.removeSaslProperty( SaslConstants.SASL_USER_BASE_DN );
120 ldapSession.removeSaslProperty( SaslConstants.SASL_MECH );
121 ldapSession.removeSaslProperty( SaslConstants.SASL_PROPS );
122 ldapSession.removeSaslProperty( SaslConstants.SASL_AUTHENT_USER );
123 }
124
125
126 private Subject getSubject( LdapServer ldapServer ) throws Exception
127 {
128 String servicePrincipalName = ldapServer.getSaslPrincipal();
129 KerberosPrincipal servicePrincipal = new KerberosPrincipal( servicePrincipalName );
130 GetPrincipal getPrincipal = new GetPrincipal( servicePrincipal );
131
132 PrincipalStoreEntry entry = null;
133
134 try
135 {
136 entry = findPrincipal( ldapServer, getPrincipal );
137 }
138 catch ( ServiceConfigurationException sce )
139 {
140 String message = "Service principal " + servicePrincipalName + " not found at search base DN "
141 + ldapServer.getSearchBaseDn() + ".";
142 throw new ServiceConfigurationException( message, sce );
143 }
144
145 if ( entry == null )
146 {
147 String message = "Service principal " + servicePrincipalName + " not found at search base DN "
148 + ldapServer.getSearchBaseDn() + ".";
149 throw new ServiceConfigurationException( message );
150 }
151
152 Subject subject = new Subject();
153
154 for ( EncryptionType encryptionType : entry.getKeyMap().keySet() )
155 {
156 EncryptionKey key = entry.getKeyMap().get( encryptionType );
157
158 byte[] keyBytes = key.getKeyValue();
159 int type = key.getKeyType().getOrdinal();
160 int kvno = key.getKeyVersion();
161
162 KerberosKey serviceKey = new KerberosKey( servicePrincipal, keyBytes, type, kvno );
163
164 subject.getPrivateCredentials().add( serviceKey );
165 }
166
167 return subject;
168 }
169
170
171 private PrincipalStoreEntry findPrincipal( LdapServer ldapServer, GetPrincipal getPrincipal ) throws Exception
172 {
173 CoreSession adminSession = ldapServer.getDirectoryService().getAdminSession();
174 return ( PrincipalStoreEntry ) getPrincipal.execute( adminSession, new LdapDN( ldapServer.getSearchBaseDn() ) );
175 }
176 }