Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2020-07-23 17:17:53 +10:00
commit f1b4bdbbf2
3 changed files with 31 additions and 36 deletions

View File

@ -278,7 +278,7 @@ public class OpenIdAuthenticator extends LoginAuthenticator
} }
// Attempt to login with the provided authCode // Attempt to login with the provided authCode
OpenIdCredentials credentials = new OpenIdCredentials(authCode, getRedirectUri(request), _configuration); OpenIdCredentials credentials = new OpenIdCredentials(authCode, getRedirectUri(request));
UserIdentity user = login(null, credentials, request); UserIdentity user = login(null, credentials, request);
if (user != null) if (user != null)
{ {

View File

@ -23,7 +23,6 @@ import java.util.Arrays;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.HttpClient;
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.FormRequestContent; import org.eclipse.jetty.client.util.FormRequestContent;
@ -38,7 +37,7 @@ import org.slf4j.LoggerFactory;
* *
* <p> * <p>
* This is constructed with an authorization code from the authentication request. This authorization code * This is constructed with an authorization code from the authentication request. This authorization code
* is then exchanged using {@link #redeemAuthCode(HttpClient)} for a response containing the ID Token and Access Token. * is then exchanged using {@link #redeemAuthCode(OpenIdConfiguration)} for a response containing the ID Token and Access Token.
* The response is then validated against the {@link OpenIdConfiguration}. * The response is then validated against the {@link OpenIdConfiguration}.
* </p> * </p>
*/ */
@ -48,16 +47,14 @@ public class OpenIdCredentials implements Serializable
private static final long serialVersionUID = 4766053233370044796L; private static final long serialVersionUID = 4766053233370044796L;
private final String redirectUri; private final String redirectUri;
private final OpenIdConfiguration configuration;
private String authCode; private String authCode;
private Map<String, Object> response; private Map<String, Object> response;
private Map<String, Object> claims; private Map<String, Object> claims;
public OpenIdCredentials(String authCode, String redirectUri, OpenIdConfiguration configuration) public OpenIdCredentials(String authCode, String redirectUri)
{ {
this.authCode = authCode; this.authCode = authCode;
this.redirectUri = redirectUri; this.redirectUri = redirectUri;
this.configuration = configuration;
} }
public String getUserId() public String getUserId()
@ -75,7 +72,25 @@ public class OpenIdCredentials implements Serializable
return response; return response;
} }
public void redeemAuthCode(HttpClient httpClient) throws Exception public boolean isExpired()
{
if (authCode != null || claims == null)
return true;
// Check expiry
long expiry = (Long)claims.get("exp");
long currentTimeSeconds = (long)(System.currentTimeMillis() / 1000F);
if (currentTimeSeconds > expiry)
{
if (LOG.isDebugEnabled())
LOG.debug("OpenId Credentials expired {}", this);
return true;
}
return false;
}
public void redeemAuthCode(OpenIdConfiguration configuration) throws Exception
{ {
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("redeemAuthCode() {}", this); LOG.debug("redeemAuthCode() {}", this);
@ -84,7 +99,7 @@ public class OpenIdCredentials implements Serializable
{ {
try try
{ {
response = claimAuthCode(httpClient, authCode); response = claimAuthCode(configuration);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("response: {}", response); LOG.debug("response: {}", response);
@ -103,7 +118,7 @@ public class OpenIdCredentials implements Serializable
claims = JwtDecoder.decode(idToken); claims = JwtDecoder.decode(idToken);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("claims {}", claims); LOG.debug("claims {}", claims);
validateClaims(); validateClaims(configuration);
} }
finally finally
{ {
@ -113,14 +128,14 @@ public class OpenIdCredentials implements Serializable
} }
} }
private void validateClaims() private void validateClaims(OpenIdConfiguration configuration)
{ {
// Issuer Identifier for the OpenID Provider MUST exactly match the value of the iss (issuer) Claim. // Issuer Identifier for the OpenID Provider MUST exactly match the value of the iss (issuer) Claim.
if (!configuration.getIssuer().equals(claims.get("iss"))) if (!configuration.getIssuer().equals(claims.get("iss")))
throw new IllegalArgumentException("Issuer Identifier MUST exactly match the iss Claim"); throw new IllegalArgumentException("Issuer Identifier MUST exactly match the iss Claim");
// The aud (audience) Claim MUST contain the client_id value. // The aud (audience) Claim MUST contain the client_id value.
validateAudience(); validateAudience(configuration);
// If an azp (authorized party) Claim is present, verify that its client_id is the Claim Value. // If an azp (authorized party) Claim is present, verify that its client_id is the Claim Value.
Object azp = claims.get("azp"); Object azp = claims.get("azp");
@ -128,7 +143,7 @@ public class OpenIdCredentials implements Serializable
throw new IllegalArgumentException("Authorized party claim value should be the client_id"); throw new IllegalArgumentException("Authorized party claim value should be the client_id");
} }
private void validateAudience() private void validateAudience(OpenIdConfiguration configuration)
{ {
Object aud = claims.get("aud"); Object aud = claims.get("aud");
String clientId = configuration.getClientId(); String clientId = configuration.getClientId();
@ -150,25 +165,8 @@ public class OpenIdCredentials implements Serializable
throw new IllegalArgumentException("Audience claim was not valid"); throw new IllegalArgumentException("Audience claim was not valid");
} }
public boolean isExpired() @SuppressWarnings("unchecked")
{ private Map<String, Object> claimAuthCode(OpenIdConfiguration configuration) throws Exception
if (authCode != null || claims == null)
return true;
// Check expiry
long expiry = (Long)claims.get("exp");
long currentTimeSeconds = (long)(System.currentTimeMillis() / 1000F);
if (currentTimeSeconds > expiry)
{
if (LOG.isDebugEnabled())
LOG.debug("OpenId Credentials expired {}", this);
return true;
}
return false;
}
private Map<String, Object> claimAuthCode(HttpClient httpClient, String authCode) throws Exception
{ {
Fields fields = new Fields(); Fields fields = new Fields();
fields.add("code", authCode); fields.add("code", authCode);
@ -177,7 +175,7 @@ public class OpenIdCredentials implements Serializable
fields.add("redirect_uri", redirectUri); fields.add("redirect_uri", redirectUri);
fields.add("grant_type", "authorization_code"); fields.add("grant_type", "authorization_code");
FormRequestContent formContent = new FormRequestContent(fields); FormRequestContent formContent = new FormRequestContent(fields);
Request request = httpClient.POST(configuration.getTokenEndpoint()) Request request = configuration.getHttpClient().POST(configuration.getTokenEndpoint())
.body(formContent) .body(formContent)
.timeout(10, TimeUnit.SECONDS); .timeout(10, TimeUnit.SECONDS);
ContentResponse response = request.send(); ContentResponse response = request.send();

View File

@ -22,7 +22,6 @@ import java.security.Principal;
import javax.security.auth.Subject; import javax.security.auth.Subject;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.LoginService; import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.UserIdentity;
@ -43,7 +42,6 @@ public class OpenIdLoginService extends ContainerLifeCycle implements LoginServi
private final OpenIdConfiguration configuration; private final OpenIdConfiguration configuration;
private final LoginService loginService; private final LoginService loginService;
private final HttpClient httpClient;
private IdentityService identityService; private IdentityService identityService;
private boolean authenticateNewUsers; private boolean authenticateNewUsers;
@ -63,7 +61,6 @@ public class OpenIdLoginService extends ContainerLifeCycle implements LoginServi
{ {
this.configuration = configuration; this.configuration = configuration;
this.loginService = loginService; this.loginService = loginService;
this.httpClient = configuration.getHttpClient();
addBean(this.configuration); addBean(this.configuration);
addBean(this.loginService); addBean(this.loginService);
} }
@ -88,7 +85,7 @@ public class OpenIdLoginService extends ContainerLifeCycle implements LoginServi
OpenIdCredentials openIdCredentials = (OpenIdCredentials)credentials; OpenIdCredentials openIdCredentials = (OpenIdCredentials)credentials;
try try
{ {
openIdCredentials.redeemAuthCode(httpClient); openIdCredentials.redeemAuthCode(configuration);
if (openIdCredentials.isExpired()) if (openIdCredentials.isExpired())
return null; return null;
} }