package org.pac4j.oidc.config;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.util.DefaultResourceRetriever;
import com.nimbusds.jose.util.ResourceRetriever;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.auth.*;
import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.exception.TechnicalException;
import org.pac4j.core.util.CommonHelper;
import org.pac4j.core.util.InitializableWebObject;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* OpenID Connect configuration.
*
* @author Jerome Leleu
* @since 1.9.2
*/
public class OidcConfiguration extends InitializableWebObject {
public static final String SCOPE = "scope";
public static final String RESPONSE_TYPE = "response_type";
public static final String RESPONSE_MODE = "response_mode";
public static final String REDIRECT_URI = "redirect_uri";
public static final String CLIENT_ID = "client_id";
public static final String STATE = "state";
public static final String NONCE = "nonce";
/* state attribute name in session */
public static final String STATE_SESSION_ATTRIBUTE = "oidcStateAttribute";
/* nonce attribute name in session */
public static final String NONCE_SESSION_ATTRIBUTE = "oidcNonceAttribute";
/* default max clock skew */
public static final int DEFAULT_MAX_CLOCK_SKEW = 30;
/* OpenID client identifier */
private String clientId;
/* OpenID secret */
private String secret;
/* discovery URI for fetching OP metadata (http://openid.net/specs/openid-connect-discovery-1_0.html) */
private String discoveryURI;
/* Scope */
private String scope;
/* Map containing user defined parameters */
private Map<String, String> customParams = new HashMap<>();
/* client authentication method used at token End Point */
private ClientAuthenticationMethod clientAuthenticationMethod;
/* use nonce? */
private boolean useNonce;
/* Preferred JWS algorithm */
private JWSAlgorithm preferredJwsAlgorithm;
/* max clock skew in seconds */
private int maxClockSkew = DEFAULT_MAX_CLOCK_SKEW;
/* timeouts for token and userinfo requests */
private int connectTimeout = HttpConstants.DEFAULT_CONNECT_TIMEOUT;
private int readTimeout = HttpConstants.DEFAULT_READ_TIMEOUT;
private ResourceRetriever resourceRetriever;
private OIDCProviderMetadata providerMetadata;
private String callbackUrl;
private String responseType;
private String responseMode;
private String logoutUrl;
@Override
protected void internalInit(final WebContext context) {
// checks
CommonHelper.assertNotBlank("clientId", getClientId());
CommonHelper.assertNotBlank("secret", getSecret());
if (this.getDiscoveryURI() == null && this.getProviderMetadata() == null) {
throw new TechnicalException("You must define either the discovery URL or directly the provider metadata");
}
// default value
if (getResourceRetriever() == null) {
setResourceRetriever(new DefaultResourceRetriever(getConnectTimeout(),getReadTimeout()));
}
if (this.getProviderMetadata() == null) {
CommonHelper.assertNotBlank("discoveryURI", getDiscoveryURI());
try {
// Download OIDC metadata
this.setProviderMetadata(OIDCProviderMetadata.parse(getResourceRetriever().retrieveResource(
new URL(this.getDiscoveryURI())).getContent()));
} catch (final IOException | ParseException e) {
throw new TechnicalException(e);
}
}
}
public OIDCProviderMetadata getProviderMetadata() {
return this.providerMetadata;
}
public void setProviderMetadata(final OIDCProviderMetadata providerMetadata) {
this.providerMetadata = providerMetadata;
}
public String getClientId() {
return clientId;
}
public void setClientId(final String clientId) {
this.clientId = clientId;
}
public String getSecret() {
return secret;
}
public void setSecret(final String secret) {
this.secret = secret;
}
public String getDiscoveryURI() {
return discoveryURI;
}
public void defaultDiscoveryURI(final String discoveryURI) {
if (this.discoveryURI == null) {
this.discoveryURI = discoveryURI;
}
}
public String getScope() {
return this.scope;
}
public void setScope(final String scope) {
this.scope = scope;
}
public Map<String, String> getCustomParams() {
return customParams;
}
public String getCustomParam(String name) {
return customParams.get(name);
}
public void setCustomParams(final Map<String, String> customParams) {
CommonHelper.assertNotNull("customParams", customParams);
this.customParams = customParams;
}
public void addCustomParam(final String key, final String value) {
this.customParams.put(key, value);
}
public ClientAuthenticationMethod getClientAuthenticationMethod() {
return clientAuthenticationMethod;
}
public void setClientAuthenticationMethod(final ClientAuthenticationMethod clientAuthenticationMethod) {
this.clientAuthenticationMethod = clientAuthenticationMethod;
}
public void setClientAuthenticationMethodAsString(String auth) {
this.clientAuthenticationMethod = ClientAuthenticationMethod.parse(auth);
}
public boolean isUseNonce() {
return useNonce;
}
public void setUseNonce(final boolean useNonce) {
this.useNonce = useNonce;
}
public JWSAlgorithm getPreferredJwsAlgorithm() {
return preferredJwsAlgorithm;
}
public void setPreferredJwsAlgorithm(final JWSAlgorithm preferredJwsAlgorithm) {
this.preferredJwsAlgorithm = preferredJwsAlgorithm;
}
public int getMaxClockSkew() {
return maxClockSkew;
}
public void setMaxClockSkew(final int maxClockSkew) {
this.maxClockSkew = maxClockSkew;
}
public int getConnectTimeout() {
return connectTimeout;
}
public void setConnectTimeout(final int connectTimeout) {
this.connectTimeout = connectTimeout;
}
public int getReadTimeout() {
return readTimeout;
}
public void setReadTimeout(final int readTimeout) {
this.readTimeout = readTimeout;
}
public ResourceRetriever getResourceRetriever() {
return resourceRetriever;
}
public void defaultResourceRetriever(final ResourceRetriever resourceRetriever) {
if (this.resourceRetriever == null) {
this.resourceRetriever = resourceRetriever;
}
}
public void setDiscoveryURI(final String discoveryURI) {
this.discoveryURI = discoveryURI;
}
public void setResourceRetriever(final ResourceRetriever resourceRetriever) {
this.resourceRetriever = resourceRetriever;
}
public String getCallbackUrl() {
return callbackUrl;
}
public void setCallbackUrl(final String callbackUrl) {
this.callbackUrl = callbackUrl;
}
public String getResponseType() {
return responseType;
}
public void setResponseType(final String responseType) {
this.responseType = responseType;
}
public String getResponseMode() {
return responseMode;
}
public void setResponseMode(final String responseMode) {
this.responseMode = responseMode;
}
public String getLogoutUrl() {
return logoutUrl;
}
public void setLogoutUrl(final String logoutUrl) {
this.logoutUrl = logoutUrl;
}
@Override
public String toString() {
return CommonHelper.toString(this.getClass(), "clientId", clientId, "secret", "[protected]", "discoveryURI", discoveryURI, "scope", scope,
"customParams", customParams, "clientAuthenticationMethod", clientAuthenticationMethod, "useNonce", useNonce, "preferredJwsAlgorithm", preferredJwsAlgorithm,
"maxClockSkew", maxClockSkew, "connectTimeout", connectTimeout, "readTimeout", readTimeout, "resourceRetriever", resourceRetriever,
"callbackUrl", callbackUrl, "responseType", responseType, "responseMode", responseMode, "logoutUrl", logoutUrl);
}
}