Merge pull request #6643 from eclipse/jetty-9.4.x-6617-openidBasicAuth

Issue #6617 - add support for the client_secret_basic authentication method (jetty-9.4)
This commit is contained in:
Lachlan 2021-08-19 16:18:55 +10:00 committed by GitHub
commit 3de9d3428e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 8 deletions

View File

@ -16,6 +16,7 @@
<Arg><Property name="jetty.openid.provider.tokenEndpoint"/></Arg> <Arg><Property name="jetty.openid.provider.tokenEndpoint"/></Arg>
<Arg><Property name="jetty.openid.clientId"/></Arg> <Arg><Property name="jetty.openid.clientId"/></Arg>
<Arg><Property name="jetty.openid.clientSecret"/></Arg> <Arg><Property name="jetty.openid.clientSecret"/></Arg>
<Arg><Property name="jetty.openid.authMethod" default="client_secret_post"/></Arg>
<Arg><Ref refid="HttpClient"/></Arg> <Arg><Ref refid="HttpClient"/></Arg>
<Call name="addScopes"> <Call name="addScopes">
<Arg> <Arg>

View File

@ -1,7 +1,7 @@
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html # DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description] [description]
Adds OpenId Connect authentication. Adds OpenId Connect authentication to the server.
[depend] [depend]
security security
@ -42,3 +42,6 @@ etc/jetty-openid.xml
## True if all certificates should be trusted by the default SslContextFactory ## True if all certificates should be trusted by the default SslContextFactory
# jetty.openid.sslContextFactory.trustAll=false # jetty.openid.sslContextFactory.trustAll=false
## What authentication method to use with the Token Endpoint (client_secret_post, client_secret_basic).
# jetty.openid.authMethod=client_secret_post

View File

@ -48,6 +48,7 @@ public class OpenIdConfiguration extends ContainerLifeCycle
private final String clientId; private final String clientId;
private final String clientSecret; private final String clientSecret;
private final List<String> scopes = new ArrayList<>(); private final List<String> scopes = new ArrayList<>();
private final String authMethod;
private String authEndpoint; private String authEndpoint;
private String tokenEndpoint; private String tokenEndpoint;
@ -73,6 +74,22 @@ public class OpenIdConfiguration extends ContainerLifeCycle
*/ */
public OpenIdConfiguration(String issuer, String authorizationEndpoint, String tokenEndpoint, public OpenIdConfiguration(String issuer, String authorizationEndpoint, String tokenEndpoint,
String clientId, String clientSecret, HttpClient httpClient) String clientId, String clientSecret, HttpClient httpClient)
{
this(issuer, authorizationEndpoint, tokenEndpoint, clientId, clientSecret, "client_secret_post", httpClient);
}
/**
* Create an OpenID configuration for a specific OIDC provider.
* @param issuer The URL of the OpenID provider.
* @param authorizationEndpoint the URL of the OpenID provider's authorization endpoint if configured.
* @param tokenEndpoint the URL of the OpenID provider's token endpoint if configured.
* @param clientId OAuth 2.0 Client Identifier valid at the Authorization Server.
* @param clientSecret The client secret known only by the Client and the Authorization Server.
* @param authMethod Authentication method to use with the Token Endpoint.
* @param httpClient The {@link HttpClient} instance to use.
*/
public OpenIdConfiguration(String issuer, String authorizationEndpoint, String tokenEndpoint,
String clientId, String clientSecret, String authMethod, HttpClient httpClient)
{ {
this.issuer = issuer; this.issuer = issuer;
this.clientId = clientId; this.clientId = clientId;
@ -80,6 +97,7 @@ public class OpenIdConfiguration extends ContainerLifeCycle
this.authEndpoint = authorizationEndpoint; this.authEndpoint = authorizationEndpoint;
this.tokenEndpoint = tokenEndpoint; this.tokenEndpoint = tokenEndpoint;
this.httpClient = httpClient != null ? httpClient : newHttpClient(); this.httpClient = httpClient != null ? httpClient : newHttpClient();
this.authMethod = authMethod;
if (this.issuer == null) if (this.issuer == null)
throw new IllegalArgumentException("Issuer was not configured"); throw new IllegalArgumentException("Issuer was not configured");
@ -179,6 +197,11 @@ public class OpenIdConfiguration extends ContainerLifeCycle
return tokenEndpoint; return tokenEndpoint;
} }
public String getAuthMethod()
{
return authMethod;
}
public void addScopes(String... scopes) public void addScopes(String... scopes)
{ {
if (scopes != null) if (scopes != null)

View File

@ -19,13 +19,16 @@
package org.eclipse.jetty.security.openid; package org.eclipse.jetty.security.openid;
import java.io.Serializable; import java.io.Serializable;
import java.net.URI;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.api.Authentication;
import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.BasicAuthentication;
import org.eclipse.jetty.client.util.FormContentProvider; import org.eclipse.jetty.client.util.FormContentProvider;
import org.eclipse.jetty.util.Fields; import org.eclipse.jetty.util.Fields;
import org.eclipse.jetty.util.ajax.JSON; import org.eclipse.jetty.util.ajax.JSON;
@ -173,14 +176,27 @@ public class OpenIdCredentials implements Serializable
{ {
Fields fields = new Fields(); Fields fields = new Fields();
fields.add("code", authCode); fields.add("code", authCode);
fields.add("client_id", configuration.getClientId());
fields.add("client_secret", configuration.getClientSecret());
fields.add("redirect_uri", redirectUri); fields.add("redirect_uri", redirectUri);
fields.add("grant_type", "authorization_code"); fields.add("grant_type", "authorization_code");
FormContentProvider formContentProvider = new FormContentProvider(fields);
Request request = configuration.getHttpClient().POST(configuration.getTokenEndpoint()) Request request = configuration.getHttpClient().POST(configuration.getTokenEndpoint());
.content(formContentProvider) switch (configuration.getAuthMethod())
.timeout(10, TimeUnit.SECONDS); {
case "client_secret_basic":
URI uri = URI.create(configuration.getTokenEndpoint());
Authentication.Result authentication = new BasicAuthentication.BasicResult(uri, configuration.getClientId(), configuration.getClientSecret());
authentication.apply(request);
break;
case "client_secret_post":
fields.add("client_id", configuration.getClientId());
fields.add("client_secret", configuration.getClientSecret());
break;
default:
throw new IllegalStateException(configuration.getAuthMethod());
}
FormContentProvider formContent = new FormContentProvider(fields);
request = request.content(formContent).timeout(10, TimeUnit.SECONDS);
ContentResponse response = request.send(); ContentResponse response = request.send();
String responseBody = response.getContentAsString(); String responseBody = response.getContentAsString();
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())