add changes from merge

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2022-07-04 17:53:46 +10:00
parent ab16327315
commit 4e7fa4b943
4 changed files with 90 additions and 56 deletions

View File

@ -40,6 +40,9 @@ public class OpenIdConfiguration extends ContainerLifeCycle
{ {
private static final Logger LOG = LoggerFactory.getLogger(OpenIdConfiguration.class); private static final Logger LOG = LoggerFactory.getLogger(OpenIdConfiguration.class);
private static final String CONFIG_PATH = "/.well-known/openid-configuration"; private static final String CONFIG_PATH = "/.well-known/openid-configuration";
private static final String AUTHORIZATION_ENDPOINT = "authorization_endpoint";
private static final String TOKEN_ENDPOINT = "token_endpoint";
private static final String ISSUER = "issuer";
private final HttpClient httpClient; private final HttpClient httpClient;
private final String issuer; private final String issuer;
@ -116,35 +119,45 @@ public class OpenIdConfiguration extends ContainerLifeCycle
if (authEndpoint == null || tokenEndpoint == null) if (authEndpoint == null || tokenEndpoint == null)
{ {
Map<String, Object> discoveryDocument = fetchOpenIdConnectMetadata(issuer, httpClient); Map<String, Object> discoveryDocument = fetchOpenIdConnectMetadata();
processMetadata(discoveryDocument);
authEndpoint = (String)discoveryDocument.get("authorization_endpoint");
if (authEndpoint == null)
throw new IllegalArgumentException("authorization_endpoint");
tokenEndpoint = (String)discoveryDocument.get("token_endpoint");
if (tokenEndpoint == null)
throw new IllegalArgumentException("token_endpoint");
if (!Objects.equals(discoveryDocument.get("issuer"), issuer))
LOG.warn("The issuer in the metadata is not correct.");
} }
} }
private static HttpClient newHttpClient() /**
* Process the OpenID Connect metadata discovered by {@link #fetchOpenIdConnectMetadata()}.
* By default, only the {@link #AUTHORIZATION_ENDPOINT} and {@link #TOKEN_ENDPOINT} claims are extracted.
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html">OpenID Connect Discovery 1.0</a>
* @throws IllegalStateException if a required field is not present in the metadata.
*/
protected void processMetadata(Map<String, Object> discoveryDocument)
{ {
ClientConnector connector = new ClientConnector(); authEndpoint = (String)discoveryDocument.get(AUTHORIZATION_ENDPOINT);
connector.setSslContextFactory(new SslContextFactory.Client(false)); if (authEndpoint == null)
return new HttpClient(new HttpClientTransportOverHTTP(connector)); throw new IllegalStateException(AUTHORIZATION_ENDPOINT);
tokenEndpoint = (String)discoveryDocument.get(TOKEN_ENDPOINT);
if (tokenEndpoint == null)
throw new IllegalStateException(TOKEN_ENDPOINT);
// We are lenient and not throw here as some major OIDC providers do not conform to this.
if (!Objects.equals(discoveryDocument.get(ISSUER), issuer))
LOG.warn("The issuer in the metadata is not correct.");
} }
private static Map<String, Object> fetchOpenIdConnectMetadata(String provider, HttpClient httpClient) /**
* Obtain the JSON metadata from OpenID Connect Discovery Configuration Endpoint.
* @return a set of Claims about the OpenID Provider's configuration in JSON format.
* @throws IllegalStateException if metadata could not be fetched from the OP.
*/
protected Map<String, Object> fetchOpenIdConnectMetadata()
{ {
String provider = issuer;
if (provider.endsWith("/"))
provider = provider.substring(0, provider.length() - 1);
try try
{ {
if (provider.endsWith("/"))
provider = provider.substring(0, provider.length() - 1);
Map<String, Object> result; Map<String, Object> result;
String responseBody = httpClient.GET(provider + CONFIG_PATH).getContentAsString(); String responseBody = httpClient.GET(provider + CONFIG_PATH).getContentAsString();
Object parsedResult = new JSON().fromJSON(responseBody); Object parsedResult = new JSON().fromJSON(responseBody);
@ -153,8 +166,8 @@ public class OpenIdConfiguration extends ContainerLifeCycle
{ {
Map<?, ?> rawResult = (Map<?, ?>)parsedResult; Map<?, ?> rawResult = (Map<?, ?>)parsedResult;
result = rawResult.entrySet().stream() result = rawResult.entrySet().stream()
.filter(entry -> entry.getValue() != null) .filter(entry -> entry.getValue() != null)
.collect(Collectors.toMap(it -> it.getKey().toString(), Map.Entry::getValue)); .collect(Collectors.toMap(it -> it.getKey().toString(), Map.Entry::getValue));
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("discovery document {}", result); LOG.debug("discovery document {}", result);
return result; return result;
@ -167,7 +180,7 @@ public class OpenIdConfiguration extends ContainerLifeCycle
} }
catch (Exception e) catch (Exception e)
{ {
throw new IllegalArgumentException("invalid identity provider " + provider, e); throw new IllegalStateException("invalid identity provider " + provider, e);
} }
} }
@ -227,6 +240,13 @@ public class OpenIdConfiguration extends ContainerLifeCycle
this.authenticateNewUsers = authenticateNewUsers; this.authenticateNewUsers = authenticateNewUsers;
} }
private static HttpClient newHttpClient()
{
ClientConnector connector = new ClientConnector();
connector.setSslContextFactory(new SslContextFactory.Client(false));
return new HttpClient(new HttpClientTransportOverHTTP(connector));
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -113,11 +113,8 @@ public class DeferredAuthentication implements Authentication.Deferred
if (security != null) if (security != null)
{ {
security.logout(null); security.logout(null);
if (_authenticator instanceof LoginAuthenticator) _authenticator.logout(request);
{ return new LoggedOutAuthentication(_authenticator);
((LoginAuthenticator)_authenticator).logout(request);
return new LoggedOutAuthentication((LoginAuthenticator)_authenticator);
}
} }
return Authentication.UNAUTHENTICATED; return Authentication.UNAUTHENTICATED;

View File

@ -40,6 +40,9 @@ public class OpenIdConfiguration extends ContainerLifeCycle
{ {
private static final Logger LOG = LoggerFactory.getLogger(OpenIdConfiguration.class); private static final Logger LOG = LoggerFactory.getLogger(OpenIdConfiguration.class);
private static final String CONFIG_PATH = "/.well-known/openid-configuration"; private static final String CONFIG_PATH = "/.well-known/openid-configuration";
private static final String AUTHORIZATION_ENDPOINT = "authorization_endpoint";
private static final String TOKEN_ENDPOINT = "token_endpoint";
private static final String ISSUER = "issuer";
private final HttpClient httpClient; private final HttpClient httpClient;
private final String issuer; private final String issuer;
@ -116,35 +119,45 @@ public class OpenIdConfiguration extends ContainerLifeCycle
if (authEndpoint == null || tokenEndpoint == null) if (authEndpoint == null || tokenEndpoint == null)
{ {
Map<String, Object> discoveryDocument = fetchOpenIdConnectMetadata(issuer, httpClient); Map<String, Object> discoveryDocument = fetchOpenIdConnectMetadata();
processMetadata(discoveryDocument);
authEndpoint = (String)discoveryDocument.get("authorization_endpoint");
if (authEndpoint == null)
throw new IllegalArgumentException("authorization_endpoint");
tokenEndpoint = (String)discoveryDocument.get("token_endpoint");
if (tokenEndpoint == null)
throw new IllegalArgumentException("token_endpoint");
if (!Objects.equals(discoveryDocument.get("issuer"), issuer))
LOG.warn("The issuer in the metadata is not correct.");
} }
} }
private static HttpClient newHttpClient() /**
* Process the OpenID Connect metadata discovered by {@link #fetchOpenIdConnectMetadata()}.
* By default, only the {@link #AUTHORIZATION_ENDPOINT} and {@link #TOKEN_ENDPOINT} claims are extracted.
* @see <a href="https://openid.net/specs/openid-connect-discovery-1_0.html">OpenID Connect Discovery 1.0</a>
* @throws IllegalStateException if a required field is not present in the metadata.
*/
protected void processMetadata(Map<String, Object> discoveryDocument)
{ {
ClientConnector connector = new ClientConnector(); authEndpoint = (String)discoveryDocument.get(AUTHORIZATION_ENDPOINT);
connector.setSslContextFactory(new SslContextFactory.Client(false)); if (authEndpoint == null)
return new HttpClient(new HttpClientTransportOverHTTP(connector)); throw new IllegalStateException(AUTHORIZATION_ENDPOINT);
tokenEndpoint = (String)discoveryDocument.get(TOKEN_ENDPOINT);
if (tokenEndpoint == null)
throw new IllegalStateException(TOKEN_ENDPOINT);
// We are lenient and not throw here as some major OIDC providers do not conform to this.
if (!Objects.equals(discoveryDocument.get(ISSUER), issuer))
LOG.warn("The issuer in the metadata is not correct.");
} }
private static Map<String, Object> fetchOpenIdConnectMetadata(String provider, HttpClient httpClient) /**
* Obtain the JSON metadata from OpenID Connect Discovery Configuration Endpoint.
* @return a set of Claims about the OpenID Provider's configuration in JSON format.
* @throws IllegalStateException if metadata could not be fetched from the OP.
*/
protected Map<String, Object> fetchOpenIdConnectMetadata()
{ {
String provider = issuer;
if (provider.endsWith("/"))
provider = provider.substring(0, provider.length() - 1);
try try
{ {
if (provider.endsWith("/"))
provider = provider.substring(0, provider.length() - 1);
Map<String, Object> result; Map<String, Object> result;
String responseBody = httpClient.GET(provider + CONFIG_PATH).getContentAsString(); String responseBody = httpClient.GET(provider + CONFIG_PATH).getContentAsString();
Object parsedResult = new JSON().fromJSON(responseBody); Object parsedResult = new JSON().fromJSON(responseBody);
@ -153,8 +166,8 @@ public class OpenIdConfiguration extends ContainerLifeCycle
{ {
Map<?, ?> rawResult = (Map<?, ?>)parsedResult; Map<?, ?> rawResult = (Map<?, ?>)parsedResult;
result = rawResult.entrySet().stream() result = rawResult.entrySet().stream()
.filter(entry -> entry.getValue() != null) .filter(entry -> entry.getValue() != null)
.collect(Collectors.toMap(it -> it.getKey().toString(), Map.Entry::getValue)); .collect(Collectors.toMap(it -> it.getKey().toString(), Map.Entry::getValue));
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("discovery document {}", result); LOG.debug("discovery document {}", result);
return result; return result;
@ -167,7 +180,7 @@ public class OpenIdConfiguration extends ContainerLifeCycle
} }
catch (Exception e) catch (Exception e)
{ {
throw new IllegalArgumentException("invalid identity provider " + provider, e); throw new IllegalStateException("invalid identity provider " + provider, e);
} }
} }
@ -227,6 +240,13 @@ public class OpenIdConfiguration extends ContainerLifeCycle
this.authenticateNewUsers = authenticateNewUsers; this.authenticateNewUsers = authenticateNewUsers;
} }
private static HttpClient newHttpClient()
{
ClientConnector connector = new ClientConnector();
connector.setSslContextFactory(new SslContextFactory.Client(false));
return new HttpClient(new HttpClientTransportOverHTTP(connector));
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -120,11 +120,8 @@ public class DeferredAuthentication implements Authentication.Deferred
if (security != null) if (security != null)
{ {
security.logout(null); security.logout(null);
if (_authenticator instanceof LoginAuthenticator) _authenticator.logout(request);
{ return new LoggedOutAuthentication(_authenticator);
((LoginAuthenticator)_authenticator).logout(request);
return new LoggedOutAuthentication((LoginAuthenticator)_authenticator);
}
} }
return Authentication.UNAUTHENTICATED; return Authentication.UNAUTHENTICATED;