View Javadoc
1   /*
2    * Copyright 2013–2019 Michael Osipov
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.michaelo.tomcat.realm.mapper;
17  
18  import java.util.Locale;
19  
20  import javax.naming.Name;
21  import javax.naming.NameParser;
22  import javax.naming.NamingException;
23  import javax.naming.directory.DirContext;
24  
25  import org.apache.commons.lang3.StringUtils;
26  import org.ietf.jgss.GSSName;
27  
28  /**
29   * A mapper for the AD attribute {@code sAMAccountName} and the realm. This mapper splits the GSS
30   * name in the primary and realm component. The instance component is completely ignored. The
31   * primary component is assigned to the {@code sAMAccountName} and the realm is transformed to a
32   * search base according to <a href="https://tools.ietf.org/html/rfc2247">RFC 2247</a>. Moreover,
33   * this implementation mimics
34   * <a href="https://docs.microsoft.com/de-de/windows/win32/api/ntdsapi/nf-ntdsapi-dscracknamesw">
35   * {@code DsCrackNames}</a> with {@code formatOffered} set to {@code DS_USER_PRINCIPAL_NAME} and
36   * {@code formatDesired} set to {@code DS_FQDN_1779_NAME}. Verified against <a href=
37   * "https://github.com/samba-team/samba/blob/7ed24924d2917556a03c51eadcb65b3e3c1e8af6/source4/dsdb/samdb/cracknames.c#L1260">
38   * Samba's implementation</a> of {@code DsCrackNames}.
39   * <p>
40   * <strong>Note:</strong> This mapper requires to operate from the {@code RootDSE} of a domain
41   * controller or better yet, a GC. No root DN normalization (stripping DC components) happens here
42   * (yet).
43   *
44   * @version $Id: SamAccountNameRfc2247Mapper.java 336 2019-11-22 11:45:45Z michael-o $
45   */
46  public class SamAccountNameRfc2247Mapper extends SamAccountNameMapper {
47  
48  	public synchronized MappedValues map(DirContext context, GSSName gssName)
49  			throws NamingException {
50  
51  		String[] upnComponents = StringUtils.split(gssName.toString(), '@');
52  		String samAccountName = upnComponents[0];
53  		String realm = upnComponents[1];
54  		String searchBase = StringUtils.EMPTY;
55  
56  		String[] realmComponents = StringUtils.split(realm, '.');
57  		NameParser parser = context.getNameParser(StringUtils.EMPTY);
58  		Name searchBaseName = parser.parse(StringUtils.EMPTY);
59  
60  		for (int i = realmComponents.length - 1; i >= 0; i--) {
61  			searchBaseName.add("DC=" + realmComponents[i].toLowerCase(Locale.ROOT));
62  		}
63  
64  		searchBase = searchBaseName.toString();
65  
66  		return new SamAccountNameMappedValues(searchBase, samAccountName);
67  
68  	}
69  }