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