Skip to content

Commit

Permalink
[ELY-2584] Add the ability to specify that the OIDC Authentication Re…
Browse files Browse the repository at this point in the history
…quest should include request and request_uri parameters
  • Loading branch information
PrarthonaPaul committed Feb 26, 2024
1 parent 2bbdcfc commit cd4478d
Show file tree
Hide file tree
Showing 17 changed files with 1,074 additions and 81 deletions.
16 changes: 16 additions & 0 deletions http/oidc/pom.xml
Expand Up @@ -128,6 +128,11 @@
<artifactId>keycloak-admin-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>jboss-logmanager</artifactId>
Expand Down Expand Up @@ -173,6 +178,17 @@
<artifactId>jmockit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-credential-source-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wildfly.security</groupId>
<artifactId>wildfly-elytron-tests-common</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down
Expand Up @@ -19,6 +19,7 @@
package org.wildfly.security.http.oidc;

import static org.jboss.logging.Logger.Level.ERROR;
import static org.jboss.logging.Logger.Level.INFO;
import static org.jboss.logging.Logger.Level.WARN;
import static org.jboss.logging.annotations.Message.NONE;

Expand Down Expand Up @@ -233,5 +234,20 @@ interface ElytronMessages extends BasicLogger {
@Message(id = 23056, value = "No message entity")
IOException noMessageEntity();

@Message(id = 23057, value = "Invalid keystore configuration for signing Request Objects.")
IOException invalidKeyStoreConfiguration();

@Message(id = 23058, value = "The signature algorithm specified is not supported by the OpenID Provider.")
IOException invalidRequestObjectSignatureAlgorithm();

@Message(id = 23059, value = "The encryption algorithm specified is not supported by the OpenID Provider.")
IOException invalidRequestObjectEncryptionAlgorithm();

@Message(id = 23060, value = "The content encryption algorithm specified is not supported by the OpenID Provider.")
IOException invalidRequestObjectContentEncryptionAlgorithm();

@LogMessage(level = INFO)
@Message(id = 23061, value = "The OpenID provider does not support request parameters. Sending the request using OAuth2 format.")
void requestParameterNotSupported();
}

@@ -0,0 +1,44 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2020 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed 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.wildfly.security.http.oidc;

import static org.apache.http.HttpHeaders.ACCEPT;
import static org.wildfly.security.http.oidc.Oidc.JSON_CONTENT_TYPE;

import java.io.IOException;
import org.apache.http.client.methods.HttpGet;
import org.jose4j.lang.JoseException;
import org.wildfly.security.jose.jwk.JsonWebKeySet;
/**
* A public key locator that dynamically obtains the public key from an OpenID
* provider by sending a request to the provider's {@code jwks_uri} when needed.
*
* @author <a href="mailto:prpaul@redhat.com">Prarthona Paul</a>
* */
public class JWKPublicKeySetExtractor implements OidcPublicKeyExtractor {
public JWKPublicKeySetExtractor() {
}
@Override
public JsonWebKeySet extractPublicKeySet(OidcClientConfiguration config) throws IOException, JoseException {
HttpGet request = new HttpGet(config.getJwksUrl());
request.addHeader(ACCEPT, JSON_CONTENT_TYPE);
return Oidc.sendJsonHttpRequest(config, request, JsonWebKeySet.class);
}

}
Expand Up @@ -22,15 +22,9 @@
import static org.wildfly.security.http.oidc.Oidc.CLIENT_ASSERTION;
import static org.wildfly.security.http.oidc.Oidc.CLIENT_ASSERTION_TYPE;
import static org.wildfly.security.http.oidc.Oidc.CLIENT_ASSERTION_TYPE_JWT;
import static org.wildfly.security.http.oidc.Oidc.PROTOCOL_CLASSPATH;
import static org.wildfly.security.http.oidc.Oidc.asInt;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;
Expand Down Expand Up @@ -115,7 +109,7 @@ public void init(OidcClientConfiguration oidcClientConfiguration, Object credent
clientKeyAlias = oidcClientConfiguration.getResourceName();
}

KeyPair keyPair = loadKeyPairFromKeyStore(clientKeyStoreFile, clientKeyStorePassword, clientKeyPassword, clientKeyAlias, clientKeyStoreType);
KeyPair keyPair = new JWTSigningUtils().loadKeyPairFromKeyStore(clientKeyStoreFile, clientKeyStorePassword, clientKeyPassword, clientKeyAlias, clientKeyStoreType);
setupKeyPair(keyPair);
this.tokenTimeout = asInt(cfg, "token-timeout", 10);
}
Expand Down Expand Up @@ -155,43 +149,4 @@ protected JwtClaims createRequestToken(String clientId, String tokenUrl) {
jwtClaims.setExpirationTime(exp);
return jwtClaims;
}

private static KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType) {
InputStream stream = findFile(keyStoreFile);
try {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(stream, storePassword.toCharArray());
PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyPassword.toCharArray());
if (privateKey == null) {
log.unableToLoadKeyWithAlias(keyAlias);
}
PublicKey publicKey = keyStore.getCertificate(keyAlias).getPublicKey();
return new KeyPair(publicKey, privateKey);
} catch (Exception e) {
throw log.unableToLoadPrivateKey(e);
}
}

private static InputStream findFile(String keystoreFile) {
if (keystoreFile.startsWith(PROTOCOL_CLASSPATH)) {
String classPathLocation = keystoreFile.replace(PROTOCOL_CLASSPATH, "");
// try current class classloader first
InputStream is = JWTClientCredentialsProvider.class.getClassLoader().getResourceAsStream(classPathLocation);
if (is == null) {
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(classPathLocation);
}
if (is != null) {
return is;
} else {
throw log.unableToFindKeystoreFile(keystoreFile);
}
} else {
try {
// fallback to file
return new FileInputStream(keystoreFile);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}
@@ -0,0 +1,46 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2023 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed 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.wildfly.security.http.oidc;

import java.io.InputStream;
import java.security.KeyPair;

/**
* An interface to obtain the KeyPair from a keystore file.
*
* @author <a href="mailto:prpaul@redhat.com">Prarthona Paul</a>
*/

public interface JWTSigning {
/**
* @param keyStoreFile the path to the keystore file
* @param storePassword the password for the keystore file
* @param keyPassword the password for the key we would like ot extract from the keystore
* @param keyAlias the alias for the key that uniquely identifies it
* @param keyStoreType the type of keystore we are trying to access
* @return the private-public keypair extracted from the keystore
*/
KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType);

/**
* @param keystoreFile the path the keystore file we are trying to access
* @return the contents of the file as an inputStream
*/
InputStream findFile(String keystoreFile);
}
@@ -0,0 +1,81 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2020 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed 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.wildfly.security.http.oidc;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;

import static org.wildfly.security.http.oidc.ElytronMessages.log;
import static org.wildfly.security.http.oidc.Oidc.PROTOCOL_CLASSPATH;

/**
* An interface to obtain the KeyPair from a keystore file.
*
* @author <a href="mailto:prpaul@redhat.com">Prarthona Paul</a>
*/

public class JWTSigningUtils implements JWTSigning{
public JWTSigningUtils() {}

@Override
public KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType) {
InputStream stream = findFile(keyStoreFile);
try {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(stream, storePassword.toCharArray());
PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyAlias, keyPassword.toCharArray());
if (privateKey == null) {
log.unableToLoadKeyWithAlias(keyAlias);
}
PublicKey publicKey = keyStore.getCertificate(keyAlias).getPublicKey();
return new KeyPair(publicKey, privateKey);
} catch (Exception e) {
throw log.unableToLoadPrivateKey(e);
}
}

@Override
public InputStream findFile(String keystoreFile) {
if (keystoreFile.startsWith(PROTOCOL_CLASSPATH)) {
String classPathLocation = keystoreFile.replace(PROTOCOL_CLASSPATH, "");
// try current class classloader first
InputStream is = JWTClientCredentialsProvider.class.getClassLoader().getResourceAsStream(classPathLocation);
if (is == null) {
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(classPathLocation);
}
if (is != null) {
return is;
} else {
throw log.unableToFindKeystoreFile(keystoreFile);
}
} else {
try {
// fallback to file
return new FileInputStream(keystoreFile);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}
23 changes: 23 additions & 0 deletions http/oidc/src/main/java/org/wildfly/security/http/oidc/Oidc.java
Expand Up @@ -73,6 +73,8 @@ public class Oidc {
public static final String PARTIAL = "partial/";
public static final String PASSWORD = "password";
public static final String PROMPT = "prompt";
public static final String REQUEST = "request";
public static final String REQUEST_URI = "request_uri";
public static final String SCOPE = "scope";
public static final String UI_LOCALES = "ui_locales";
public static final String USERNAME = "username";
Expand Down Expand Up @@ -199,6 +201,27 @@ public enum TokenStore {
COOKIE
}

public enum AuthenticationFormat {
REQUEST_TYPE_OAUTH2("oauth2"),
REQUEST_TYPE_REQUEST("request"),
REQUEST_TYPE_REQUEST_URI("request_uri");

private final String value;

AuthenticationFormat(String value) {
this.value = value;
}

/**
* Get the string value for this referral mode.
*
* @return the string value for this referral mode
*/
public String getValue() {
return value;
}
}

public enum ClientCredentialsProviderType {
SECRET("secret"),
JWT("jwt"),
Expand Down

0 comments on commit cd4478d

Please sign in to comment.