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.

GssApiMechanisms.java 5.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch> and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.internal.transport.sshd;
  11. import java.net.InetAddress;
  12. import java.net.InetSocketAddress;
  13. import java.net.UnknownHostException;
  14. import java.util.Collection;
  15. import java.util.Collections;
  16. import java.util.LinkedHashMap;
  17. import java.util.Map;
  18. import java.util.concurrent.atomic.AtomicBoolean;
  19. import org.eclipse.jgit.annotations.NonNull;
  20. import org.ietf.jgss.GSSContext;
  21. import org.ietf.jgss.GSSException;
  22. import org.ietf.jgss.GSSManager;
  23. import org.ietf.jgss.GSSName;
  24. import org.ietf.jgss.Oid;
  25. /**
  26. * Global repository of GSS-API mechanisms that we can use.
  27. */
  28. public class GssApiMechanisms {
  29. private GssApiMechanisms() {
  30. // No instantiation
  31. }
  32. /** Prefix to use with {@link GSSName#NT_HOSTBASED_SERVICE}. */
  33. public static final String GSSAPI_HOST_PREFIX = "host@"; //$NON-NLS-1$
  34. /** The {@link Oid} of Kerberos 5. */
  35. public static final Oid KERBEROS_5 = createOid("1.2.840.113554.1.2.2"); //$NON-NLS-1$
  36. /** SGNEGO is not to be used with ssh. */
  37. public static final Oid SPNEGO = createOid("1.3.6.1.5.5.2"); //$NON-NLS-1$
  38. /** Protects {@link #supportedMechanisms}. */
  39. private static final Object LOCK = new Object();
  40. /**
  41. * The {@link AtomicBoolean} is set to {@code true} when the mechanism could
  42. * be initialized successfully at least once.
  43. */
  44. private static Map<Oid, Boolean> supportedMechanisms;
  45. /**
  46. * Retrieves an immutable collection of the supported mechanisms.
  47. *
  48. * @return the supported mechanisms
  49. */
  50. @NonNull
  51. public static Collection<Oid> getSupportedMechanisms() {
  52. synchronized (LOCK) {
  53. if (supportedMechanisms == null) {
  54. GSSManager manager = GSSManager.getInstance();
  55. Oid[] mechs = manager.getMechs();
  56. Map<Oid, Boolean> mechanisms = new LinkedHashMap<>();
  57. if (mechs != null) {
  58. for (Oid oid : mechs) {
  59. mechanisms.put(oid, Boolean.FALSE);
  60. }
  61. }
  62. supportedMechanisms = mechanisms;
  63. }
  64. return Collections.unmodifiableSet(supportedMechanisms.keySet());
  65. }
  66. }
  67. /**
  68. * Report that this mechanism was used successfully.
  69. *
  70. * @param mechanism
  71. * that worked
  72. */
  73. public static void worked(@NonNull Oid mechanism) {
  74. synchronized (LOCK) {
  75. supportedMechanisms.put(mechanism, Boolean.TRUE);
  76. }
  77. }
  78. /**
  79. * Mark the mechanisms as failed.
  80. *
  81. * @param mechanism
  82. * to mark
  83. */
  84. public static void failed(@NonNull Oid mechanism) {
  85. synchronized (LOCK) {
  86. Boolean worked = supportedMechanisms.get(mechanism);
  87. if (worked != null && !worked.booleanValue()) {
  88. // If it never worked, remove it
  89. supportedMechanisms.remove(mechanism);
  90. }
  91. }
  92. }
  93. /**
  94. * Resolves an {@link InetSocketAddress}.
  95. *
  96. * @param remote
  97. * to resolve
  98. * @return the resolved {@link InetAddress}, or {@code null} if unresolved.
  99. */
  100. public static InetAddress resolve(@NonNull InetSocketAddress remote) {
  101. InetAddress address = remote.getAddress();
  102. if (address == null) {
  103. try {
  104. address = InetAddress.getByName(remote.getHostString());
  105. } catch (UnknownHostException e) {
  106. return null;
  107. }
  108. }
  109. return address;
  110. }
  111. /**
  112. * Determines a canonical host name for use use with GSS-API.
  113. *
  114. * @param remote
  115. * to get the host name from
  116. * @return the canonical host name, if it can be determined, otherwise the
  117. * {@link InetSocketAddress#getHostString() unprocessed host name}.
  118. */
  119. @NonNull
  120. public static String getCanonicalName(@NonNull InetSocketAddress remote) {
  121. InetAddress address = resolve(remote);
  122. if (address == null) {
  123. return remote.getHostString();
  124. }
  125. return address.getCanonicalHostName();
  126. }
  127. /**
  128. * Creates a {@link GSSContext} for the given mechanism to authenticate with
  129. * the host given by {@code fqdn}.
  130. *
  131. * @param mechanism
  132. * {@link Oid} of the mechanism to use
  133. * @param fqdn
  134. * fully qualified domain name of the host to authenticate with
  135. * @return the context, if the mechanism is available and the context could
  136. * be created, or {@code null} otherwise
  137. */
  138. public static GSSContext createContext(@NonNull Oid mechanism,
  139. @NonNull String fqdn) {
  140. GSSContext context = null;
  141. try {
  142. GSSManager manager = GSSManager.getInstance();
  143. context = manager.createContext(
  144. manager.createName(
  145. GssApiMechanisms.GSSAPI_HOST_PREFIX + fqdn,
  146. GSSName.NT_HOSTBASED_SERVICE),
  147. mechanism, null, GSSContext.DEFAULT_LIFETIME);
  148. } catch (GSSException e) {
  149. closeContextSilently(context);
  150. failed(mechanism);
  151. return null;
  152. }
  153. worked(mechanism);
  154. return context;
  155. }
  156. /**
  157. * Closes (disposes of) a {@link GSSContext} ignoring any
  158. * {@link GSSException}s.
  159. *
  160. * @param context
  161. * to dispose
  162. */
  163. public static void closeContextSilently(GSSContext context) {
  164. if (context != null) {
  165. try {
  166. context.dispose();
  167. } catch (GSSException e) {
  168. // Ignore
  169. }
  170. }
  171. }
  172. private static Oid createOid(String rep) {
  173. try {
  174. return new Oid(rep);
  175. } catch (GSSException e) {
  176. // Does not occur
  177. return null;
  178. }
  179. }
  180. }