You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LdapAutodiscovery.java 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.auth.ldap;
  21. import java.net.InetAddress;
  22. import java.net.UnknownHostException;
  23. import java.util.ArrayList;
  24. import java.util.Collections;
  25. import java.util.List;
  26. import java.util.SortedSet;
  27. import java.util.TreeSet;
  28. import javax.naming.NamingEnumeration;
  29. import javax.naming.NamingException;
  30. import javax.naming.directory.Attribute;
  31. import javax.naming.directory.Attributes;
  32. import javax.naming.directory.DirContext;
  33. import javax.naming.directory.InitialDirContext;
  34. import org.apache.commons.lang.math.NumberUtils;
  35. import org.sonar.api.server.ServerSide;
  36. import org.sonar.api.utils.log.Logger;
  37. import org.sonar.api.utils.log.Loggers;
  38. /**
  39. * @author Evgeny Mandrikov
  40. */
  41. @ServerSide
  42. public class LdapAutodiscovery {
  43. private static final Logger LOG = Loggers.get(LdapAutodiscovery.class);
  44. /**
  45. * Get the DNS domain name (eg: example.org).
  46. *
  47. * @return DNS domain
  48. * @throws java.net.UnknownHostException if unable to determine DNS domain
  49. */
  50. public static String getDnsDomainName() throws UnknownHostException {
  51. return getDnsDomainName(InetAddress.getLocalHost().getCanonicalHostName());
  52. }
  53. /**
  54. * Extracts DNS domain name from Fully Qualified Domain Name.
  55. *
  56. * @param fqdn Fully Qualified Domain Name
  57. * @return DNS domain name or null, if can't be extracted
  58. */
  59. public static String getDnsDomainName(String fqdn) {
  60. if (fqdn.indexOf('.') == -1) {
  61. return null;
  62. }
  63. return fqdn.substring(fqdn.indexOf('.') + 1);
  64. }
  65. /**
  66. * Get the DNS DN domain (eg: dc=example,dc=org).
  67. *
  68. * @param domain DNS domain
  69. * @return DNS DN domain
  70. */
  71. public static String getDnsDomainDn(String domain) {
  72. StringBuilder result = new StringBuilder();
  73. String[] domainPart = domain.split("[.]");
  74. for (int i = 0; i < domainPart.length; i++) {
  75. result.append(i > 0 ? "," : "").append("dc=").append(domainPart[i]);
  76. }
  77. return result.toString();
  78. }
  79. /**
  80. * Get LDAP server(s) from DNS.
  81. *
  82. * @param domain DNS domain
  83. * @return LDAP server(s) or empty if unable to determine
  84. */
  85. public List<LdapSrvRecord> getLdapServers(String domain) {
  86. try {
  87. return getLdapServers(new InitialDirContext(), domain);
  88. } catch (NamingException e) {
  89. LOG.error("Unable to determine LDAP server(s) from DNS", e);
  90. return Collections.emptyList();
  91. }
  92. }
  93. List<LdapSrvRecord> getLdapServers(DirContext context, String domain) throws NamingException {
  94. Attributes lSrvAttrs = context.getAttributes("dns:/_ldap._tcp." + domain, new String[] {"srv"});
  95. Attribute serversAttribute = lSrvAttrs.get("srv");
  96. NamingEnumeration<?> lEnum = serversAttribute.getAll();
  97. SortedSet<LdapSrvRecord> result = new TreeSet<>();
  98. while (lEnum.hasMore()) {
  99. String srvRecord = (String) lEnum.next();
  100. // priority weight port target
  101. String[] srvData = srvRecord.split(" ");
  102. int priority = NumberUtils.toInt(srvData[0]);
  103. int weight = NumberUtils.toInt(srvData[1]);
  104. String port = srvData[2];
  105. String target = srvData[3];
  106. if (target.endsWith(".")) {
  107. target = target.substring(0, target.length() - 1);
  108. }
  109. String server = "ldap://" + target + ":" + port;
  110. result.add(new LdapSrvRecord(server, priority, weight));
  111. }
  112. return new ArrayList<>(result);
  113. }
  114. public static class LdapSrvRecord implements Comparable<LdapSrvRecord> {
  115. private final String serverUrl;
  116. private final int priority;
  117. private final int weight;
  118. public LdapSrvRecord(String serverUrl, int priority, int weight) {
  119. this.serverUrl = serverUrl;
  120. this.priority = priority;
  121. this.weight = weight;
  122. }
  123. @Override
  124. public int compareTo(LdapSrvRecord o) {
  125. if (this.priority == o.priority) {
  126. return Integer.compare(o.weight, this.weight);
  127. }
  128. return Integer.compare(this.priority, o.priority);
  129. }
  130. String getServerUrl() {
  131. return serverUrl;
  132. }
  133. @Override
  134. public boolean equals(Object obj) {
  135. if (this == obj) {
  136. return true;
  137. }
  138. if (obj == null || getClass() != obj.getClass()) {
  139. return false;
  140. }
  141. return this.serverUrl.equals(((LdapSrvRecord) obj).serverUrl);
  142. }
  143. @Override
  144. public int hashCode() {
  145. return this.serverUrl.hashCode();
  146. }
  147. }
  148. }