View Javadoc
1   /*
2    * Copyright 2013–2021 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.Arrays;
19  
20  import javax.naming.NamingException;
21  import javax.naming.directory.DirContext;
22  
23  import org.apache.commons.lang3.StringUtils;
24  import org.ietf.jgss.GSSException;
25  import org.ietf.jgss.GSSName;
26  import org.ietf.jgss.Oid;
27  
28  /**
29   * A mapper for the AD attribute {@code userPrincipalName}. This mapper maps the GSS name to the AD
30   * attribute {@code userPrincipalName} which by default contains the implicit UPN unless it's
31   * overwritten by the explicit (enterprise) UPN. In this case, the result will be empty. No
32   * assumption is made about the root DN set in the given context, so you can narrow down your search
33   * base if you like.
34   */
35  public class UserPrincipalNameSearchMapper implements UsernameSearchMapper {
36  
37  	protected final static Oid KRB5_NT_PRINCIPAL;
38  	protected final static Oid KRB5_NT_ENTERPRISE_PRINCIPAL;
39  	protected final static Oid MS_UPN;
40  
41  	static {
42  		try {
43  			KRB5_NT_PRINCIPAL = new Oid("1.2.840.113554.1.2.2.1");
44  		} catch (GSSException e) {
45  			throw new IllegalStateException("Failed to create OID for KRB5_NT_PRINCIPAL");
46  		}
47  
48  		try {
49  			KRB5_NT_ENTERPRISE_PRINCIPAL = new Oid("1.2.840.113554.1.2.2.6");
50  		} catch (GSSException e) {
51  			throw new IllegalStateException("Failed to create OID for KRB5_NT_ENTERPRISE_PRINCIPAL");
52  		}
53  
54  		try {
55  			MS_UPN = new Oid("1.3.6.1.4.1.311.20.2.3");
56  		} catch (GSSException e) {
57  			throw new IllegalStateException("Failed to create OID for MS_UPN");
58  		}
59  	}
60  
61  	private static final Oid[] SUPPORTED_STRING_NAME_TYPES = new Oid[] { MS_UPN, KRB5_NT_ENTERPRISE_PRINCIPAL,
62  			KRB5_NT_PRINCIPAL };
63  
64  	@Override
65  	public Oid[] getSupportedStringNameTypes() {
66  		return Arrays.copyOf(SUPPORTED_STRING_NAME_TYPES, SUPPORTED_STRING_NAME_TYPES.length);
67  	}
68  
69  	@Override
70  	public boolean supportsGssName(GSSName gssName) {
71  		try {
72  			return gssName.getStringNameType().containedIn(SUPPORTED_STRING_NAME_TYPES);
73  		} catch (GSSException e) {
74  			// Can this ever happen?
75  			return false;
76  		}
77  	}
78  
79  	protected static class UserPrincipalNameMappedValues implements MappedValues {
80  
81  		private String searchUsername;
82  
83  		protected UserPrincipalNameMappedValues(String searchUsername) {
84  			this.searchUsername = searchUsername;
85  		}
86  
87  		@Override
88  		public String getSearchBase() {
89  			return StringUtils.EMPTY;
90  		}
91  
92  		@Override
93  		public String getSearchAttributeName() {
94  			return "userPrincipalName";
95  		}
96  
97  		@Override
98  		public String getSearchUsername() {
99  			return searchUsername;
100 		}
101 
102 	}
103 
104 	public synchronized MappedValues map(DirContext context, GSSName gssName)
105 			throws NamingException {
106 		if (!supportsGssName(gssName))
107 			throw new IllegalArgumentException("GSS name '" + gssName + "' is not supported");
108 
109 		return new UserPrincipalNameMappedValues(gssName.toString());
110 	}
111 
112 }