]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/directory/ldap/IpaUtils.java
Improve ACR attribute typing.
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / directory / ldap / IpaUtils.java
1 package org.argeo.cms.directory.ldap;
2
3 import java.io.IOException;
4 import java.net.InetAddress;
5 import java.net.URI;
6 import java.net.URISyntaxException;
7 import java.util.ArrayList;
8 import java.util.Dictionary;
9 import java.util.Hashtable;
10 import java.util.List;
11 import java.util.StringJoiner;
12
13 import javax.naming.InvalidNameException;
14 import javax.naming.ldap.LdapName;
15
16 import org.argeo.api.acr.ldap.LdapAttr;
17 import org.argeo.cms.dns.DnsBrowser;
18 import org.argeo.cms.runtime.DirectoryConf;
19
20 /** Free IPA specific conventions. */
21 public class IpaUtils {
22 public final static String IPA_USER_BASE = "cn=users";
23 public final static String IPA_GROUP_BASE = "cn=groups";
24 public final static String IPA_ROLE_BASE = "cn=roles";
25 public final static String IPA_SERVICE_BASE = "cn=services";
26
27 public final static String IPA_ACCOUNTS_BASE = "cn=accounts";
28
29 private final static String KRB_PRINCIPAL_NAME = LdapAttr.krbPrincipalName.name().toLowerCase();
30
31 public final static String IPA_USER_DIRECTORY_CONFIG = DirectoryConf.userBase + "=" + IPA_USER_BASE + "&"
32 + DirectoryConf.groupBase + "=" + IPA_GROUP_BASE + "&" + DirectoryConf.systemRoleBase + "=" + IPA_ROLE_BASE
33 + "&" + DirectoryConf.readOnly + "=true";
34
35 @Deprecated
36 static String domainToUserDirectoryConfigPath(String realm) {
37 return domainToBaseDn(realm) + "?" + IPA_USER_DIRECTORY_CONFIG + "&" + DirectoryConf.realm.name() + "=" + realm;
38 }
39
40 public static void addIpaConfig(String realm, Dictionary<String, Object> properties) {
41 properties.put(DirectoryConf.baseDn.name(), domainToBaseDn(realm));
42 properties.put(DirectoryConf.realm.name(), realm);
43 properties.put(DirectoryConf.userBase.name(), IPA_USER_BASE);
44 properties.put(DirectoryConf.groupBase.name(), IPA_GROUP_BASE);
45 properties.put(DirectoryConf.systemRoleBase.name(), IPA_ROLE_BASE);
46 properties.put(DirectoryConf.readOnly.name(), Boolean.TRUE.toString());
47 }
48
49 public static String domainToBaseDn(String domain) {
50 String[] dcs = domain.split("\\.");
51 StringJoiner sj = new StringJoiner(",");
52 for (int i = 0; i < dcs.length; i++) {
53 String dc = dcs[i];
54 sj.add(LdapAttr.dc.name() + '=' + dc.toLowerCase());
55 }
56 return IPA_ACCOUNTS_BASE + ',' + sj.toString();
57 }
58
59 public static LdapName kerberosToDn(String kerberosName) {
60 String[] kname = kerberosName.split("@");
61 String username = kname[0];
62 String baseDn = domainToBaseDn(kname[1]);
63 String dn;
64 if (!username.contains("/"))
65 dn = LdapAttr.uid + "=" + username + "," + IPA_USER_BASE + "," + baseDn;
66 else
67 dn = KRB_PRINCIPAL_NAME + "=" + kerberosName + "," + IPA_SERVICE_BASE + "," + baseDn;
68 try {
69 return new LdapName(dn);
70 } catch (InvalidNameException e) {
71 throw new IllegalArgumentException("Badly formatted name for " + kerberosName + ": " + dn);
72 }
73 }
74
75 private IpaUtils() {
76
77 }
78
79 public static String kerberosDomainFromDns() {
80 String kerberosDomain;
81 try (DnsBrowser dnsBrowser = new DnsBrowser()) {
82 // TODO retrieve hostname from CMS config
83 InetAddress localhost = InetAddress.getLocalHost();
84 String hostname = localhost.getHostName();
85 int dotIndex = hostname.indexOf('.');
86 if (dotIndex <= 0) {
87 hostname = localhost.getCanonicalHostName();
88 dotIndex = hostname.indexOf('.');
89 if (dotIndex <= 0)
90 throw new IllegalArgumentException(
91 "Cannot extract DNS zone from hostname " + hostname + " (" + localhost + ")");
92 }
93 String dnsZone = hostname.substring(dotIndex + 1);
94 kerberosDomain = dnsBrowser.getRecord("_kerberos." + dnsZone, "TXT");
95 return kerberosDomain;
96 } catch (IOException e) {
97 throw new IllegalStateException("Cannot determine Kerberos domain from DNS", e);
98 }
99
100 }
101
102 public static Dictionary<String, Object> convertIpaUri(URI uri) {
103 String path = uri.getPath();
104 String kerberosRealm;
105 if (path == null || path.length() <= 1) {
106 kerberosRealm = kerberosDomainFromDns();
107 } else {
108 kerberosRealm = path.substring(1);
109 }
110
111 if (kerberosRealm == null)
112 throw new IllegalStateException("No Kerberos domain available for " + uri);
113 // TODO intergrate CA certificate in truststore
114 // String schemeToUse = SCHEME_LDAPS;
115 String schemeToUse = DirectoryConf.SCHEME_LDAP;
116 List<String> ldapHosts;
117 String ldapHostsStr = uri.getHost();
118 if (ldapHostsStr == null || ldapHostsStr.trim().equals("")) {
119 try (DnsBrowser dnsBrowser = new DnsBrowser()) {
120 ldapHosts = dnsBrowser.getSrvRecordsAsHosts("_ldap._tcp." + kerberosRealm.toLowerCase(),
121 schemeToUse.equals(DirectoryConf.SCHEME_LDAP) ? true : false);
122 if (ldapHosts == null || ldapHosts.size() == 0) {
123 throw new IllegalStateException("Cannot configure LDAP for IPA " + uri);
124 } else {
125 ldapHostsStr = ldapHosts.get(0);
126 }
127 } catch (IOException e) {
128 throw new IllegalStateException("Cannot convert IPA uri " + uri, e);
129 }
130 } else {
131 ldapHosts = new ArrayList<>();
132 ldapHosts.add(ldapHostsStr);
133 }
134
135 StringBuilder uriStr = new StringBuilder();
136 try {
137 for (String host : ldapHosts) {
138 URI convertedUri = new URI(schemeToUse + "://" + host + "/");
139 uriStr.append(convertedUri).append(' ');
140 }
141 } catch (URISyntaxException e) {
142 throw new IllegalStateException("Cannot convert IPA uri " + uri, e);
143 }
144
145 Hashtable<String, Object> res = new Hashtable<>();
146 res.put(DirectoryConf.uri.name(), uriStr.toString());
147 addIpaConfig(kerberosRealm, res);
148 return res;
149 }
150 }