- Add openid-well-known-endpoint and treat it to automatically find the :
* issuer, * authorization_endpoint, * token_endpoint, * jwks_uri - Replace openid-flow-type with openid-response-type - Use an Enum for openid-response-type to limit to the values 'id_token', 'token' or 'cod' - Treat the response type as an implicit flow type allowing use of AWS Cognito
This commit is contained in:
1 parent
4dfb4b5c66
commit
08bcd1f9e8
7 files changed
+476
-82
No files matched your search
+14
-19
@@ -63,6 +63,7 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS
|
||||
/**
|
||||
* The standard HTTP parameter which will be included within the URL by all
|
||||
* OpenID services upon successful implicit flow authentication.
|
||||
*
|
||||
*/
|
||||
public static final String IMPLICIT_TOKEN_PARAMETER_NAME = "id_token";
|
||||
|
||||
@@ -136,13 +137,13 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS
|
||||
Set<String> groups = null;
|
||||
Map<String,String> tokens = Collections.emptyMap();
|
||||
|
||||
logger.debug("OpenID authentication with {} flow (ID: {}, Secret: {}, PKCE: {})",
|
||||
confService.getFlowType(),
|
||||
logger.debug("OpenID authentication with '{}' reponse type (ID: {}, Secret: {}, PKCE: {})",
|
||||
confService.getResponseType(),
|
||||
confService.getClientID(),
|
||||
confService.getClientSecret(),
|
||||
confService.isPKCERequired());
|
||||
|
||||
if (confService.getFlowType().equals("implicit")) {
|
||||
if (confService.isImplicitFlow()) {
|
||||
String token = credentials.getParameter(IMPLICIT_TOKEN_PARAMETER_NAME);
|
||||
if (token != null) {
|
||||
JwtClaims claims = tokenService.validateToken(token);
|
||||
@@ -194,21 +195,15 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS
|
||||
|
||||
@Override
|
||||
public URI getLoginURI() throws GuacamoleException {
|
||||
if (confService.getFlowType().equals("implicit")) {
|
||||
return UriBuilder.fromUri(confService.getAuthorizationEndpoint())
|
||||
.queryParam("scope", confService.getScope())
|
||||
.queryParam("response_type", IMPLICIT_TOKEN_PARAMETER_NAME)
|
||||
.queryParam("client_id", confService.getClientID())
|
||||
.queryParam("redirect_uri", confService.getRedirectURI())
|
||||
.queryParam("nonce", nonceService.generate(confService.getMaxNonceValidity() * 60000L))
|
||||
.build();
|
||||
} else {
|
||||
UriBuilder builder = UriBuilder.fromUri(confService.getAuthorizationEndpoint())
|
||||
.queryParam("scope", confService.getScope())
|
||||
.queryParam("response_type", CODE_TOKEN_PARAMETER_NAME)
|
||||
.queryParam("client_id", confService.getClientID())
|
||||
.queryParam("redirect_uri", confService.getRedirectURI());
|
||||
UriBuilder builder = UriBuilder.fromUri(confService.getAuthorizationEndpoint())
|
||||
.queryParam("scope", confService.getScope())
|
||||
.queryParam("response_type", confService.getResponseType().toString())
|
||||
.queryParam("client_id", confService.getClientID())
|
||||
.queryParam("redirect_uri", confService.getRedirectURI());
|
||||
|
||||
if (confService.isImplicitFlow()) {
|
||||
builder.queryParam("nonce", nonceService.generate(confService.getMaxNonceValidity() * 60000L));
|
||||
} else {
|
||||
if (confService.isPKCERequired()) {
|
||||
String codeVerifier = PKCEUtil.generateCodeVerifier();
|
||||
String codeChallenge;
|
||||
@@ -230,9 +225,9 @@ public class AuthenticationProviderService implements SSOAuthenticationProviderS
|
||||
.queryParam("code_challenge_method", "S256")
|
||||
.queryParam(AUTH_SESSION_QUERY_PARAM, identifier);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
@@ -21,8 +21,10 @@ package org.apache.guacamole.auth.openid;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.Singleton;
|
||||
import org.apache.guacamole.auth.openid.conf.ConfigurationService;
|
||||
import org.apache.guacamole.auth.openid.conf.OpenIDEnvironment;
|
||||
import org.apache.guacamole.auth.openid.conf.OpenIDWellKnown;
|
||||
import org.apache.guacamole.auth.openid.OpenIDAuthenticationSessionManager;
|
||||
import org.apache.guacamole.auth.sso.NonceService;
|
||||
import org.apache.guacamole.auth.openid.token.TokenValidationService;
|
||||
|
||||
+77
-18
@@ -20,13 +20,17 @@
|
||||
package org.apache.guacamole.auth.openid.conf;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.apache.guacamole.auth.openid.conf.OpenIDResponseType;
|
||||
import org.apache.guacamole.auth.openid.conf.OpenIDWellKnown;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.environment.Environment;
|
||||
import org.apache.guacamole.properties.BooleanGuacamoleProperty;
|
||||
import org.apache.guacamole.properties.EnumGuacamoleProperty;
|
||||
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
|
||||
import org.apache.guacamole.properties.StringGuacamoleProperty;
|
||||
import org.apache.guacamole.properties.URIGuacamoleProperty;
|
||||
@@ -38,9 +42,9 @@ import org.apache.guacamole.properties.URIGuacamoleProperty;
|
||||
public class ConfigurationService {
|
||||
|
||||
/**
|
||||
* The default OICD flow type
|
||||
* The default OICD reponse type
|
||||
*/
|
||||
private static final String DEFAULT_FLOW_TYPE = "implicit";
|
||||
private static final OpenIDResponseType DEFAULT_RESPONSE_TYPE = OpenIDResponseType.ID_TOKEN;
|
||||
|
||||
/**
|
||||
* The default claim type to use to retrieve an authenticated user's
|
||||
@@ -128,13 +132,13 @@ public class ConfigurationService {
|
||||
};
|
||||
|
||||
/**
|
||||
* The flow type of the OpenID service.
|
||||
* The reponse type of the OpenID service.
|
||||
*/
|
||||
private static final StringGuacamoleProperty OPENID_FLOW_TYPE =
|
||||
new StringGuacamoleProperty() {
|
||||
private static final EnumGuacamoleProperty<OpenIDResponseType> OPENID_RESPONSE_TYPE =
|
||||
new EnumGuacamoleProperty<OpenIDResponseType>(OpenIDResponseType.class) {
|
||||
|
||||
@Override
|
||||
public String getName() { return "openid-flow-type"; }
|
||||
public String getName() { return "openid-response-type"; }
|
||||
|
||||
};
|
||||
|
||||
@@ -316,6 +320,12 @@ public class ConfigurationService {
|
||||
*/
|
||||
@Inject
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Service for retrieving OpenID well-known data.
|
||||
*/
|
||||
@Inject
|
||||
private OpenIDWellKnown confWellKnown;
|
||||
|
||||
/**
|
||||
* Returns the authorization endpoint (URI) of the OpenID service as
|
||||
@@ -326,11 +336,15 @@ public class ConfigurationService {
|
||||
* guacamole.properties.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed, or if the authorization
|
||||
* endpoint property is missing.
|
||||
*/
|
||||
public URI getAuthorizationEndpoint() throws GuacamoleException {
|
||||
return environment.getRequiredProperty(OPENID_AUTHORIZATION_ENDPOINT);
|
||||
URI authorization_endpoint = environment.getProperty(OPENID_AUTHORIZATION_ENDPOINT);
|
||||
authorization_endpoint = authorization_endpoint == null ? confWellKnown.getAuthorizationEndpoint() : authorization_endpoint;
|
||||
if (authorization_endpoint == null) {
|
||||
throw new GuacamoleException("Property openid-authorization-endpoint or openid-well-known-endpoint is required");
|
||||
}
|
||||
return authorization_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,7 +396,12 @@ public class ConfigurationService {
|
||||
* is missing.
|
||||
*/
|
||||
public String getIssuer() throws GuacamoleException {
|
||||
return environment.getRequiredProperty(OPENID_ISSUER);
|
||||
String issuer = environment.getProperty(OPENID_ISSUER);
|
||||
issuer = issuer == null ? confWellKnown.getIssuer() : issuer;
|
||||
if (issuer == null) {
|
||||
throw new GuacamoleException("Property openid-issuer or openid-well-known-endpoint is required");
|
||||
}
|
||||
return issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,7 +419,12 @@ public class ConfigurationService {
|
||||
* property is missing.
|
||||
*/
|
||||
public URI getJWKSEndpoint() throws GuacamoleException {
|
||||
return environment.getRequiredProperty(OPENID_JWKS_ENDPOINT);
|
||||
URI jwks_uri = environment.getProperty(OPENID_JWKS_ENDPOINT);
|
||||
jwks_uri = jwks_uri == null ? confWellKnown.getJWKSEndpoint() : jwks_uri;
|
||||
if (jwks_uri == null) {
|
||||
throw new GuacamoleException("Property openid-jwks-endpoint or openid-well-known-endpoint is required");
|
||||
}
|
||||
return jwks_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,25 +436,60 @@ public class ConfigurationService {
|
||||
* guacamole.properties.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed, or if the authorization
|
||||
* If guacamole.properties cannot be parsed, or if the token
|
||||
* endpoint property is missing.
|
||||
*/
|
||||
public URI getTokenEndpoint() throws GuacamoleException {
|
||||
return environment.getRequiredProperty(OPENID_TOKEN_ENDPOINT);
|
||||
URI token_endpoint = environment.getProperty(OPENID_TOKEN_ENDPOINT);
|
||||
token_endpoint = token_endpoint == null ? confWellKnown.getTokenEndpoint() : token_endpoint;
|
||||
if (token_endpoint == null) {
|
||||
throw new GuacamoleException("Property openid-token-endpoint or openid-well-known-endpoint is required");
|
||||
}
|
||||
return token_endpoint;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the flow type of the OpenID service as configured with guacamole.properties.
|
||||
* Returns the well-known endpoint (URI) of the OIDC service as
|
||||
* configured with guacamole.properties.
|
||||
*
|
||||
* @return
|
||||
* The flow type of the OpenID service, as configured with guacamole.properties. Can
|
||||
* be either 'implicit' or 'code'.
|
||||
* The well-known endpoint of the OIDC service, as configured with
|
||||
* guacamole.properties.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed, or if the well-known
|
||||
* endpoint property is missing.
|
||||
*/
|
||||
public URI getWellKnownEndpoint() throws GuacamoleException {
|
||||
return confWellKnown.getWellKnownEndpoint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reponse type of the OpenID service as configured with guacamole.properties.
|
||||
*
|
||||
* @return
|
||||
* The reponse type of the OpenID service, as configured with guacamole.properties. Can
|
||||
* be either 'id_token', 'token' or 'code'.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
public String getFlowType() throws GuacamoleException {
|
||||
return environment.getProperty(OPENID_FLOW_TYPE, DEFAULT_FLOW_TYPE);
|
||||
public OpenIDResponseType getResponseType() throws GuacamoleException {
|
||||
return environment.getProperty(OPENID_RESPONSE_TYPE, DEFAULT_RESPONSE_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the response type defines an implict flow
|
||||
*
|
||||
* @return
|
||||
* The whether implicit flow is used or not, as configured with guacamole.properties.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed.
|
||||
*/
|
||||
public boolean isImplicitFlow() throws GuacamoleException {
|
||||
OpenIDResponseType response_type = environment.getProperty(OPENID_RESPONSE_TYPE, DEFAULT_RESPONSE_TYPE);
|
||||
return response_type != OpenIDResponseType.CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.guacamole.auth.openid.conf;
|
||||
|
||||
import org.apache.guacamole.properties.EnumGuacamoleProperty.PropertyValue;
|
||||
|
||||
/**
|
||||
* This enum represents the valid OIDC reponse types that can be used
|
||||
*/
|
||||
public enum OpenIDResponseType {
|
||||
/*
|
||||
* Response type "id_token" used for implciit flow as specified in the OpenID standard
|
||||
*/
|
||||
@PropertyValue("id_token")
|
||||
ID_TOKEN("id_token"),
|
||||
|
||||
/* Response type "token" used for implicit flow by certain Identity Providers, notably
|
||||
* AWS Cognito. This corresponds to the official OIDC response_type "id_token token"
|
||||
* that returns both the "id_token" and "access_token" parameters
|
||||
*/
|
||||
@PropertyValue("token")
|
||||
TOKEN("token"),
|
||||
|
||||
/**
|
||||
* Response type "code" used for code flow authentication
|
||||
*/
|
||||
@PropertyValue("code")
|
||||
CODE("code");
|
||||
|
||||
/*
|
||||
* The string value of the response type used
|
||||
*/
|
||||
public final String STRING_VALUE;
|
||||
|
||||
/**
|
||||
* Initializes the response type such that it is associated with the
|
||||
* given string value.
|
||||
*
|
||||
* @param value
|
||||
* The string value that will be associated with the enum value.
|
||||
*/
|
||||
private OpenIDResponseType(String value) {
|
||||
this.STRING_VALUE = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return STRING_VALUE;
|
||||
}
|
||||
}
|
||||
+214
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.guacamole.auth.openid.conf;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Map;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import org.apache.guacamole.auth.openid.util.JsonUrlReader;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.environment.Environment;
|
||||
import org.apache.guacamole.properties.URIGuacamoleProperty;
|
||||
import org.jose4j.json.JsonUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Class for retrieving well-known endpoint data.
|
||||
*/
|
||||
@Singleton
|
||||
public class OpenIDWellKnown {
|
||||
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private final Logger logger = LoggerFactory.getLogger(OpenIDWellKnown.class);
|
||||
|
||||
|
||||
/**
|
||||
* The number of attempts to the well-known endpoint to get the values before giving up
|
||||
*/
|
||||
private static final int MAX_ATTEMPTS = 24;
|
||||
|
||||
/**
|
||||
* The delay between each attempt to well-known endpoint in seconds
|
||||
*/
|
||||
private static final long DELAY_SECONDS = 5;
|
||||
|
||||
/**
|
||||
* The detected issuer
|
||||
*/
|
||||
private static String issuer = null;
|
||||
|
||||
/**
|
||||
* The detected authorization edpoint
|
||||
*/
|
||||
private static URI authorization_endpoint = null;
|
||||
|
||||
/**
|
||||
* The detected token edpoint
|
||||
*/
|
||||
private static URI token_endpoint = null;
|
||||
|
||||
/**
|
||||
* The detected jwks_uri
|
||||
*/
|
||||
private static URI jwks_uri = null;
|
||||
|
||||
/**
|
||||
* The well-known endpoint (URI) of the OIDC service.
|
||||
*/
|
||||
private static final URIGuacamoleProperty OPENID_WELL_KNOWN_ENDPOINT =
|
||||
new URIGuacamoleProperty() {
|
||||
@Override
|
||||
public String getName() {
|
||||
return "openid-well-known-endpoint";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the well-known endpoint (URI) of the OIDC service as
|
||||
* configured with guacamole.properties.
|
||||
*
|
||||
* @return
|
||||
* The well-known endpoint of the OIDC service, as configured with
|
||||
* guacamole.properties.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If guacamole.properties cannot be parsed, or if the authorization
|
||||
* endpoint property is missing.
|
||||
*/
|
||||
public URI getWellKnownEndpoint() throws GuacamoleException {
|
||||
return environment.getProperty(OPENID_WELL_KNOWN_ENDPOINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the issuer to expect for all received ID tokens, as configured
|
||||
* from the well_known endpoint.
|
||||
*
|
||||
* @return
|
||||
* The issuer to expect for all received ID tokens, as returned by the
|
||||
* well-known endpoint.
|
||||
*/
|
||||
public String getIssuer() {
|
||||
return issuer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authorization endpoint (URI) of the OpenID service as
|
||||
* configured from the well_known endpoint.
|
||||
*
|
||||
* @return
|
||||
* The authorization endpoint of the OpenID service, as returned by the
|
||||
* well-known endpoint.
|
||||
*/
|
||||
public URI getAuthorizationEndpoint() {
|
||||
return authorization_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the token endpoint (URI) of the OpenID service as
|
||||
* configured from the well_known endpoint.
|
||||
*
|
||||
* @return
|
||||
* The token endpoint of the OpenID service, as returned by the
|
||||
* well-known endpoint.
|
||||
*/
|
||||
public URI getTokenEndpoint() {
|
||||
return token_endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the endpoint (URI) of the JWKS service which defines how
|
||||
* received ID tokens (JWTs) shall be validated, as configured from
|
||||
* the well-known endpoint.
|
||||
*
|
||||
* @return
|
||||
* The endpoint (URI) of the JWKS service which defines how received ID
|
||||
* tokens (JWTs) shall be validated, as configured from the
|
||||
* well-known endpoint.
|
||||
*/
|
||||
public URI getJWKSEndpoint() {
|
||||
return jwks_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Guacamole server environment.
|
||||
*/
|
||||
@Inject
|
||||
private Environment environment;
|
||||
|
||||
/*
|
||||
* Creates an OpenIDWellKnown class that reads the json from an OIDC
|
||||
* well-known endpoint and saves these values for later use. Use Guice
|
||||
* to ensure environment exists before initializing.
|
||||
*/
|
||||
public OpenIDWellKnown() {
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void init() {
|
||||
// Call to well-known endpoint might fail, so allow several tries before giving up
|
||||
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
|
||||
Runnable task = new Runnable() {
|
||||
int attempts = 0;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
attempts++;
|
||||
|
||||
try {
|
||||
Map<String,Object> json = JsonUrlReader.fetch("GET", getWellKnownEndpoint().toURL(), "");
|
||||
issuer = (String) json.get("issuer");
|
||||
authorization_endpoint = UriBuilder.fromUri((String) json.get("authorization_endpoint")).build();
|
||||
token_endpoint = UriBuilder.fromUri((String) json.get("token_endpoint")).build();
|
||||
jwks_uri = UriBuilder.fromUri((String) json.get("jwks_uri")).build();
|
||||
|
||||
logger.debug("OIDC well-known\n" +
|
||||
" issuer : {}\n" +
|
||||
" authorization_endpoint : {}\n" +
|
||||
" token_endpoint : {}\n" +
|
||||
" jwks_uri : {}\n",
|
||||
issuer, authorization_endpoint, token_endpoint, jwks_uri);
|
||||
|
||||
scheduler.shutdown();
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
logger.debug("Rejecting well-known endpoint : {}", e.getMessage());
|
||||
}
|
||||
|
||||
if (attempts >= MAX_ATTEMPTS) {
|
||||
logger.info("Timeout on well-known on endpoint");
|
||||
scheduler.shutdown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scheduler.scheduleAtFixedRate(task, 0, DELAY_SECONDS, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
+4
-45
@@ -20,11 +20,6 @@
|
||||
package org.apache.guacamole.auth.openid.token;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -39,6 +34,7 @@ import java.util.Set;
|
||||
import javax.ws.rs.core.UriBuilder;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.openid.conf.ConfigurationService;
|
||||
import org.apache.guacamole.auth.openid.util.JsonUrlReader;
|
||||
import org.apache.guacamole.auth.sso.NonceService;
|
||||
import org.apache.guacamole.token.TokenName;
|
||||
import org.jose4j.json.JsonUtil;
|
||||
@@ -243,46 +239,9 @@ public class TokenValidationService {
|
||||
bodyBuilder.append("&").append(urlencode("code_verifier", verifier));
|
||||
}
|
||||
|
||||
// Build the final URI and convert to a URL
|
||||
URL url = confService.getTokenEndpoint().toURL();
|
||||
|
||||
// Open connection, using HttpURLConnection
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setDoOutput(true);
|
||||
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"
|
||||
);
|
||||
|
||||
try (OutputStream out = conn.getOutputStream()) {
|
||||
byte [] body = bodyBuilder.toString().getBytes(StandardCharsets.UTF_8);
|
||||
out.write(body, 0, body.length);
|
||||
}
|
||||
|
||||
// Read response
|
||||
int status = conn.getResponseCode();
|
||||
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
status >= 200 && status < 300
|
||||
? conn.getInputStream()
|
||||
: conn.getErrorStream(),
|
||||
StandardCharsets.UTF_8
|
||||
)
|
||||
);
|
||||
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
responseBody.append(line);
|
||||
}
|
||||
reader.close();
|
||||
|
||||
Map<String,Object> json = JsonUtil.parseJson(responseBody.toString());
|
||||
|
||||
if (status < 200 || status >= 300) {
|
||||
throw new GuacamoleException("Token endpoint error (" + status + "): " + json.toString());
|
||||
}
|
||||
Map<String,Object> json =
|
||||
JsonUrlReader.fetch("POST", confService.getTokenEndpoint().toURL(),
|
||||
bodyBuilder.toString());
|
||||
|
||||
return (String) json.get("id_token");
|
||||
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.guacamole.auth.openid.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.jose4j.json.JsonUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/*
|
||||
* Utility class to open a http connection to a URL, send a body
|
||||
* and receive a response in the form of a parsed JSON
|
||||
*/
|
||||
public final class JsonUrlReader {
|
||||
/**
|
||||
* Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = LoggerFactory.getLogger(JsonUrlReader.class);
|
||||
|
||||
private JsonUrlReader() {}
|
||||
|
||||
public static Map<String,Object> fetch(String method, URL url, String body) throws GuacamoleException {
|
||||
if (url == null) {
|
||||
throw new GuacamoleException("JsonUrlReader : Missing URL");
|
||||
}
|
||||
|
||||
try {
|
||||
// Open connection, using HttpURLConnection
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
|
||||
conn.setRequestMethod(method);
|
||||
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||
|
||||
if (! method.equalsIgnoreCase("GET")) {
|
||||
conn.setDoOutput(true);
|
||||
try (OutputStream out = conn.getOutputStream()) {
|
||||
byte [] bodyBytes = body.getBytes(StandardCharsets.UTF_8);
|
||||
out.write(bodyBytes, 0, bodyBytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
// Read response
|
||||
int status = conn.getResponseCode();
|
||||
|
||||
BufferedReader reader = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
status >= 200 && status < 300
|
||||
? conn.getInputStream()
|
||||
: conn.getErrorStream(),
|
||||
StandardCharsets.UTF_8
|
||||
)
|
||||
);
|
||||
|
||||
StringBuilder responseBody = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
responseBody.append(line);
|
||||
}
|
||||
reader.close();
|
||||
|
||||
logger.debug("Response body : {}", responseBody.toString());
|
||||
|
||||
Map<String,Object> json = JsonUtil.parseJson(responseBody.toString());
|
||||
|
||||
if (status < 200 || status >= 300) {
|
||||
throw new GuacamoleException("(status: " + status + "): " + json.toString());
|
||||
}
|
||||
|
||||
return json;
|
||||
} catch (Exception e) {
|
||||
throw new GuacamoleException("JsonUrlreader error : " + method + " : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user