| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.directory.server.kerberos.sam; |
| |
| |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Map; |
| |
| import javax.naming.NamingException; |
| import javax.naming.directory.DirContext; |
| import javax.security.auth.kerberos.KerberosKey; |
| |
| import org.apache.directory.server.kerberos.shared.messages.value.types.SamType; |
| import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry; |
| |
| |
| /** |
| * The Subsystem that enables the Kerberos server to use plugable Single-use |
| * Authentication mechanisms. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| * @version $Rev$ |
| */ |
| public final class SamSubsystem |
| { |
| /** the property key base used for SAM algorithm verifiers */ |
| public static final String PROPKEY_BASE = "kerberos.sam.type."; |
| |
| /** the SAM subsystem instance */ |
| public static SamSubsystem instance; |
| |
| /** a map of verifiers so we do not need to create a new one every time */ |
| private final Map<SamType, SamVerifier> verifiers = new HashMap<SamType, SamVerifier>(); |
| |
| /** the key integrity checker used by the subsystem for all sam types */ |
| private KeyIntegrityChecker keyChecker; |
| |
| /** the user context the SamSubsystem would use to verify passwords */ |
| private DirContext userContext; |
| private String userBaseRdn; |
| |
| |
| /** |
| * Gets the singleton instance of the SamSubsystem. |
| * |
| * @return the singleton for the SamSubsystem |
| */ |
| public static SamSubsystem getInstance() |
| { |
| if ( instance == null ) |
| { |
| instance = new SamSubsystem(); |
| } |
| |
| return instance; |
| } |
| |
| |
| /** |
| * Sets the KeyIntegrityChecker used by the entire SamSubsystem. |
| * |
| * @param keyChecker the KeyIntegrityChecker used by the entire SamSubsystem |
| */ |
| public void setIntegrityChecker( KeyIntegrityChecker keyChecker ) |
| { |
| this.keyChecker = keyChecker; |
| } |
| |
| |
| /** |
| * Uses the principal entry information to load the approapriate SamVerifier |
| * and verify the Single-use password. |
| * |
| * @param entry the store entry for the Kerberos principal |
| * @param sad the single-use authentication data encrypted timestamp payload |
| * @return true if verification passed, false otherwise |
| * @throws SamException thrown when there is a failure within the verifier |
| * or a verifier cannot be found. |
| */ |
| public KerberosKey verify( PrincipalStoreEntry entry, byte[] sad ) throws SamException |
| { |
| SamVerifier verifier = null; |
| |
| if ( keyChecker == null ) |
| { |
| throw new IllegalStateException( "SamSubsystem not enabled with key integrity checker" ); |
| } |
| |
| if ( entry.getSamType() == null ) |
| { |
| throw new SamException( entry.getSamType(), "Entry has null SAM type" ); |
| } |
| |
| if ( verifiers.containsKey( entry.getSamType() ) ) |
| { |
| verifier = verifiers.get( entry.getSamType() ); |
| |
| return verifier.verify( entry.getPrincipal(), sad ); |
| } |
| |
| String key = PROPKEY_BASE + entry.getSamType().getOrdinal(); |
| |
| Hashtable<Object, Object> env = new Hashtable<Object, Object>(); |
| |
| try |
| { |
| env.putAll( userContext.getEnvironment() ); |
| } |
| catch ( NamingException e ) |
| { |
| e.printStackTrace(); |
| } |
| |
| if ( !env.containsKey( key ) ) |
| { |
| String msg = "Could not find property '" + key + "'"; |
| |
| throw new SamException( entry.getSamType(), msg ); |
| } |
| |
| String fqcn = ( String ) env.get( key ); |
| |
| try |
| { |
| Class c = Class.forName( fqcn ); |
| |
| verifier = ( SamVerifier ) c.newInstance(); |
| |
| try |
| { |
| verifier.setUserContext( ( DirContext ) userContext.lookup( userBaseRdn ) ); |
| } |
| catch ( NamingException e ) |
| { |
| e.printStackTrace(); |
| |
| } |
| |
| verifier.setIntegrityChecker( keyChecker ); |
| |
| verifier.startup(); |
| |
| if ( !verifier.getSamType().equals( entry.getSamType() ) ) |
| { |
| String msg = "Expecting entries with SAM type of " + verifier.getSamType(); |
| |
| msg += " but got a type of entry with SAM type of " + entry.getSamType(); |
| |
| throw new SamException( entry.getSamType(), msg ); |
| } |
| |
| verifiers.put( verifier.getSamType(), verifier ); |
| |
| return verifier.verify( entry.getPrincipal(), sad ); |
| } |
| catch ( ClassNotFoundException e ) |
| { |
| String msg = "Could not find verifier class '" + fqcn; |
| |
| msg += "' for SamType( " + entry.getSamType() + " ) "; |
| |
| throw new SamException( entry.getSamType(), msg, e ); |
| } |
| catch ( IllegalAccessException e ) |
| { |
| String msg = "No public default constructor on class '" + fqcn; |
| |
| msg += "' for SamType( " + entry.getSamType() + " ) "; |
| |
| throw new SamException( entry.getSamType(), msg, e ); |
| } |
| catch ( InstantiationException e ) |
| { |
| String msg = "Failed on default constructor invocation for class '" + fqcn; |
| |
| msg += "' for SamType( " + entry.getSamType() + " ) "; |
| |
| throw new SamException( entry.getSamType(), msg, e ); |
| } |
| } |
| |
| |
| /** |
| * Sets the context under which user entries can be found. |
| * |
| * @param userContext the jndi context under which users can be found. |
| * @param userBaseRdn the container with users |
| */ |
| public void setUserContext( DirContext userContext, String userBaseRdn ) |
| { |
| this.userContext = userContext; |
| this.userBaseRdn = userBaseRdn; |
| } |
| } |