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.kerberos.sam; 021 022 023import java.util.EnumMap; 024import java.util.Hashtable; 025 026import javax.naming.NamingException; 027import javax.naming.directory.DirContext; 028import javax.security.auth.kerberos.KerberosKey; 029 030import org.apache.directory.server.i18n.I18n; 031import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry; 032import org.apache.directory.shared.kerberos.codec.types.SamType; 033 034 035/** 036 * The Subsystem that enables the Kerberos server to use plugable Single-use 037 * Authentication mechanisms. 038 * 039 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 040 */ 041public final class SamSubsystem 042{ 043 /** the property key base used for SAM algorithm verifiers */ 044 public static final String PROPKEY_BASE = "kerberos.sam.type."; 045 046 /** the SAM subsystem instance */ 047 private static SamSubsystem instance; 048 049 /** a map of verifiers so we do not need to create a new one every time */ 050 private final EnumMap<SamType, SamVerifier> verifiers = new EnumMap<>( SamType.class ); 051 052 /** the key integrity checker used by the subsystem for all sam types */ 053 private KeyIntegrityChecker keyChecker; 054 055 /** the user context the SamSubsystem would use to verify passwords */ 056 private DirContext userContext; 057 private String userBaseRdn; 058 059 060 /** 061 * Gets the singleton instance of the SamSubsystem. 062 * 063 * @return the singleton for the SamSubsystem 064 */ 065 public static SamSubsystem getInstance() 066 { 067 if ( instance == null ) 068 { 069 instance = new SamSubsystem(); 070 } 071 072 return instance; 073 } 074 075 076 /** 077 * Sets the KeyIntegrityChecker used by the entire SamSubsystem. 078 * 079 * @param keyChecker the KeyIntegrityChecker used by the entire SamSubsystem 080 */ 081 public void setIntegrityChecker( KeyIntegrityChecker keyChecker ) 082 { 083 this.keyChecker = keyChecker; 084 } 085 086 087 /** 088 * Uses the principal entry information to load the approapriate SamVerifier 089 * and verify the Single-use password. 090 * 091 * @param entry the store entry for the Kerberos principal 092 * @param sad the single-use authentication data encrypted timestamp payload 093 * @return true if verification passed, false otherwise 094 * @throws SamException thrown when there is a failure within the verifier 095 * or a verifier cannot be found. 096 */ 097 public KerberosKey verify( PrincipalStoreEntry entry, byte[] sad ) throws SamException 098 { 099 SamVerifier verifier = null; 100 101 if ( keyChecker == null ) 102 { 103 throw new IllegalStateException( I18n.err( I18n.ERR_651 ) ); 104 } 105 106 if ( entry.getSamType() == null ) 107 { 108 throw new SamException( entry.getSamType(), I18n.err( I18n.ERR_652 ) ); 109 } 110 111 if ( verifiers.containsKey( entry.getSamType() ) ) 112 { 113 verifier = verifiers.get( entry.getSamType() ); 114 115 return verifier.verify( entry.getPrincipal(), sad ); 116 } 117 118 String key = PROPKEY_BASE + entry.getSamType().getOrdinal(); 119 120 Hashtable<Object, Object> env = new Hashtable<>(); 121 122 try 123 { 124 env.putAll( userContext.getEnvironment() ); 125 } 126 catch ( NamingException e ) 127 { 128 e.printStackTrace(); 129 } 130 131 if ( !env.containsKey( key ) ) 132 { 133 String msg = I18n.err( I18n.ERR_653, key ); 134 135 throw new SamException( entry.getSamType(), msg ); 136 } 137 138 String fqcn = ( String ) env.get( key ); 139 140 try 141 { 142 Class c = Class.forName( fqcn ); 143 144 verifier = ( SamVerifier ) c.newInstance(); 145 146 try 147 { 148 verifier.setUserContext( ( DirContext ) userContext.lookup( userBaseRdn ) ); 149 } 150 catch ( NamingException e ) 151 { 152 e.printStackTrace(); 153 154 } 155 156 verifier.setIntegrityChecker( keyChecker ); 157 158 verifier.startup(); 159 160 if ( !verifier.getSamType().equals( entry.getSamType() ) ) 161 { 162 String msg = I18n.err( I18n.ERR_654, verifier.getSamType(), entry.getSamType() ); 163 164 throw new SamException( entry.getSamType(), msg ); 165 } 166 167 verifiers.put( verifier.getSamType(), verifier ); 168 169 return verifier.verify( entry.getPrincipal(), sad ); 170 } 171 catch ( ClassNotFoundException e ) 172 { 173 String msg = I18n.err( I18n.ERR_655, fqcn, entry.getSamType() ); 174 175 throw new SamException( entry.getSamType(), msg, e ); 176 } 177 catch ( IllegalAccessException e ) 178 { 179 String msg = I18n.err( I18n.ERR_656, fqcn, entry.getSamType() ); 180 181 throw new SamException( entry.getSamType(), msg, e ); 182 } 183 catch ( InstantiationException e ) 184 { 185 String msg = I18n.err( I18n.ERR_657, fqcn, entry.getSamType() ); 186 187 throw new SamException( entry.getSamType(), msg, e ); 188 } 189 } 190 191 192 /** 193 * Sets the context under which user entries can be found. 194 * 195 * @param userContext the jndi context under which users can be found. 196 * @param userBaseRdn the container with users 197 */ 198 public void setUserContext( DirContext userContext, String userBaseRdn ) 199 { 200 this.userContext = userContext; 201 this.userBaseRdn = userBaseRdn; 202 } 203}