View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.kerberos.sam;
21  
22  
23  import java.util.EnumMap;
24  import java.util.Hashtable;
25  
26  import javax.naming.NamingException;
27  import javax.naming.directory.DirContext;
28  import javax.security.auth.kerberos.KerberosKey;
29  
30  import org.apache.directory.server.i18n.I18n;
31  import org.apache.directory.server.kerberos.shared.store.PrincipalStoreEntry;
32  import org.apache.directory.shared.kerberos.codec.types.SamType;
33  
34  
35  /**
36   * The Subsystem that enables the Kerberos server to use plugable Single-use
37   * Authentication mechanisms.
38   *
39   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
40   */
41  public final class SamSubsystem
42  {
43      /** the property key base used for SAM algorithm verifiers */
44      public static final String PROPKEY_BASE = "kerberos.sam.type.";
45  
46      /** the SAM subsystem instance */
47      private static SamSubsystem instance;
48  
49      /** a map of verifiers so we do not need to create a new one every time */
50      private final EnumMap<SamType, SamVerifier> verifiers = new EnumMap<>( SamType.class );
51  
52      /** the key integrity checker used by the subsystem for all sam types */
53      private KeyIntegrityChecker keyChecker;
54  
55      /** the user context the SamSubsystem would use to verify passwords */
56      private DirContext userContext;
57      private String userBaseRdn;
58  
59  
60      /**
61       * Gets the singleton instance of the SamSubsystem.
62       *
63       * @return the singleton for the SamSubsystem
64       */
65      public static SamSubsystem getInstance()
66      {
67          if ( instance == null )
68          {
69              instance = new SamSubsystem();
70          }
71  
72          return instance;
73      }
74  
75  
76      /**
77       * Sets the KeyIntegrityChecker used by the entire SamSubsystem.
78       *
79       * @param keyChecker the KeyIntegrityChecker used by the entire SamSubsystem
80       */
81      public void setIntegrityChecker( KeyIntegrityChecker keyChecker )
82      {
83          this.keyChecker = keyChecker;
84      }
85  
86  
87      /**
88       * Uses the principal entry information to load the approapriate SamVerifier
89       * and verify the Single-use password.
90       *
91       * @param entry the store entry for the Kerberos principal
92       * @param sad the single-use authentication data encrypted timestamp payload
93       * @return true if verification passed, false otherwise
94       * @throws SamException thrown when there is a failure within the verifier
95       * or a verifier cannot be found.
96       */
97      public KerberosKey verify( PrincipalStoreEntry entry, byte[] sad ) throws SamException
98      {
99          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 }