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.ldap.handlers.sasl.gssapi; 021 022 023import java.security.PrivilegedExceptionAction; 024import java.util.HashMap; 025import java.util.Map; 026 027import javax.security.auth.Subject; 028import javax.security.auth.callback.CallbackHandler; 029import javax.security.auth.kerberos.KerberosKey; 030import javax.security.auth.kerberos.KerberosPrincipal; 031import javax.security.sasl.Sasl; 032import javax.security.sasl.SaslServer; 033 034import org.apache.directory.api.ldap.model.constants.SupportedSaslMechanisms; 035import org.apache.directory.api.ldap.model.message.BindRequest; 036import org.apache.directory.api.ldap.model.name.Dn; 037import org.apache.directory.server.core.api.CoreSession; 038import org.apache.directory.server.i18n.I18n; 039import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry; 040import org.apache.directory.server.protocol.shared.kerberos.GetPrincipal; 041import org.apache.directory.server.ldap.LdapServer; 042import org.apache.directory.server.ldap.LdapSession; 043import org.apache.directory.server.ldap.handlers.sasl.AbstractMechanismHandler; 044import org.apache.directory.server.ldap.handlers.sasl.SaslConstants; 045import org.apache.directory.server.protocol.shared.ServiceConfigurationException; 046import org.apache.directory.shared.kerberos.codec.types.EncryptionType; 047import org.apache.directory.shared.kerberos.components.EncryptionKey; 048 049 050/** 051 * The GSSAPI Sasl mechanism handler. 052 * 053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 054 */ 055public class GssapiMechanismHandler extends AbstractMechanismHandler 056{ 057 public SaslServer handleMechanism( LdapSession ldapSession, BindRequest bindRequest ) throws Exception 058 { 059 SaslServer ss = ( SaslServer ) ldapSession.getSaslProperty( SaslConstants.SASL_SERVER ); 060 061 if ( ss == null ) 062 { 063 Subject subject = getSubject( ldapSession.getLdapServer() ); 064 final String saslHost = ( String ) ldapSession.getSaslProperty( SaslConstants.SASL_HOST ); 065 final Map<String, String> saslProps = ( Map<String, String> ) ldapSession 066 .getSaslProperty( SaslConstants.SASL_PROPS ); 067 068 CoreSession adminSession = ldapSession.getLdapServer().getDirectoryService().getAdminSession(); 069 070 final CallbackHandler callbackHandler = new GssapiCallbackHandler( ldapSession, adminSession, bindRequest ); 071 072 ss = Subject.doAs( subject, new PrivilegedExceptionAction<SaslServer>() 073 { 074 public SaslServer run() throws Exception 075 { 076 return Sasl.createSaslServer( SupportedSaslMechanisms.GSSAPI, SaslConstants.LDAP_PROTOCOL, 077 saslHost, saslProps, callbackHandler ); 078 } 079 } ); 080 081 ldapSession.putSaslProperty( SaslConstants.SASL_SERVER, ss ); 082 } 083 084 return ss; 085 } 086 087 088 /** 089 * {@inheritDoc} 090 */ 091 public void init( LdapSession ldapSession ) 092 { 093 // Store the host in the ldap session 094 String saslHost = ldapSession.getLdapServer().getSaslHost(); 095 ldapSession.putSaslProperty( SaslConstants.SASL_HOST, saslHost ); 096 097 Map<String, String> saslProps = new HashMap<>(); 098 saslProps.put( Sasl.QOP, ldapSession.getLdapServer().getSaslQopString() ); 099 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 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}