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 }