New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ELY-2584] Add the ability to specify that the OIDC Authentication Request should include request and request_uri parameters #1984
base: 2.x
Are you sure you want to change the base?
Conversation
93dc491
to
3ce624a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PrarthonaPaul Looks good! I've just had a quick look at it and added some minor comments, I'll look at it more and its affiliated wildfly PR later this week
http/oidc/pom.xml
Outdated
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-services</artifactId> | ||
<version>3.1.0.Final</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PrarthonaPaul Just a minor, please put a version as a property to the properties tag in the parent pom
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Skyllarr
I am not sure how to do this. Do you have an example of this being done for another dependency?
Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PrarthonaPaul In the parent pom.xml we have properties tag where you can find versions of libraries, see here. Place your keycloak-services dependency there. Then, as with other libraries in that parent pom.xml, place your dependency to the dependencyManagement tag the same way as other deps are. Then you can just use this dependency in child modules without having to specify a version. So in http/oidc/pom.xml you will then be able to place it without a version tag
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
I have updated the pom files to reflect this.
@@ -156,7 +156,7 @@ protected JwtClaims createRequestToken(String clientId, String tokenUrl) { | |||
return jwtClaims; | |||
} | |||
|
|||
private static KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType) { | |||
public static KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PrarthonaPaul Just a minor, can this method be protected instead of public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I have changed it to protected.
@@ -41,12 +41,13 @@ | |||
"expose-token", "bearer-only", "autodetect-bearer-only", | |||
"connection-pool-size", | |||
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password", | |||
"client-keystore", "client-keystore-password", "client-key-password", | |||
"client-keystore-file", "client-keystore-password", "client-key-password", "client-key-alias", "client-keystore-type", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PrarthonaPaul Just a minor, should the "client-keystore" stay here as possible configuration property because of backwards compatibility? Users could have been using it before?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh! Thanks for noticing it! I have fixed it! Also changed the class to add a new variable called clientKeyStoreFile that's different from clientKeystore along with a getter and setter for that.
deployment.setClientKeyStore(deployment.getClientKeyStore().replace(PROTOCOL_CLASSPATH, Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource("")).getPath())); | ||
} | ||
if (!deployment.getRequestSignatureAlgorithm().equals(NONE) && deployment.getClientKeyStore() == null){ | ||
throw new RuntimeException("Invalid keystore configuration for signing Request Objects."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PrarthonaPaul Just a minor, please put this exception into the ElytronMessages class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added! Thanks
} | ||
|
||
private static KeyStore createEmptyKeyStore() throws IOException, GeneralSecurityException { | ||
KeyStore keyStore = KeyStore.getInstance("JKS"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a minor, let's not forget to change this from JKS to PKCS12
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
Thanks for going though the code!
3ce624a
to
aa4ac31
Compare
} else { | ||
// send request as usual | ||
redirectUriBuilder.addParameter(REDIRECT_URI, redirectUri) | ||
.addParameter(STATE, state) | ||
.addParameters(forwardedQueryParams); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently if request
or request_uri
is not supported, then the authentication is sent as usual.
However, we can change it so that if it is not supported, then we throw a runtime error.
Another thing we can do, is keep it as is, but add a log message saying "Request/request_uri is not supported by the OpenID provider. Request is sent using the Oauth2 format"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PrarthonaPaul Thinking.. this should be discussed in the proposal, I see you asked me this there as well. If the authentication is sent as oauth
despite a different configuration it has to be logged as a minimum.
I think we should log this and then document that the request
and the request_uri
methods are used only if available with the OpenID provider, if not available a warning message will be logged. I will write this on the proposal as well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have fixed the elytron code and the docs to reflect it.
Will change it in the proposal as well. Thanks!
http/oidc/pom.xml
Outdated
<dependency> | ||
<groupId>org.keycloak</groupId> | ||
<artifactId>keycloak-services</artifactId> | ||
<version>3.1.0.Final</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @Skyllarr
I am not sure how to do this. Do you have an example of this being done for another dependency?
Thanks!
@@ -156,7 +156,7 @@ protected JwtClaims createRequestToken(String clientId, String tokenUrl) { | |||
return jwtClaims; | |||
} | |||
|
|||
private static KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType) { | |||
public static KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I have changed it to protected.
@@ -41,12 +41,13 @@ | |||
"expose-token", "bearer-only", "autodetect-bearer-only", | |||
"connection-pool-size", | |||
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password", | |||
"client-keystore", "client-keystore-password", "client-key-password", | |||
"client-keystore-file", "client-keystore-password", "client-key-password", "client-key-alias", "client-keystore-type", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh! Thanks for noticing it! I have fixed it! Also changed the class to add a new variable called clientKeyStoreFile that's different from clientKeystore along with a getter and setter for that.
deployment.setClientKeyStore(deployment.getClientKeyStore().replace(PROTOCOL_CLASSPATH, Objects.requireNonNull(Thread.currentThread().getContextClassLoader().getResource("")).getPath())); | ||
} | ||
if (!deployment.getRequestSignatureAlgorithm().equals(NONE) && deployment.getClientKeyStore() == null){ | ||
throw new RuntimeException("Invalid keystore configuration for signing Request Objects."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added! Thanks
} | ||
|
||
private static KeyStore createEmptyKeyStore() throws IOException, GeneralSecurityException { | ||
KeyStore keyStore = KeyStore.getInstance("JKS"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
Thanks for going though the code!
} else if (deployment.getRequestSignatureAlgorithm().contains(HS_256) | ||
|| deployment.getRequestSignatureAlgorithm().contains(HS_384) | ||
|| deployment.getRequestSignatureAlgorithm().contains(HS_512)) { //signed with symmetric key | ||
jsonWebSignature.setAlgorithmHeaderValue(deployment.getRequestSignatureAlgorithm()); | ||
Key key = new HmacKey(deployment.getResourceCredentials().get("secret").toString().getBytes(StandardCharsets.UTF_8)); //the client secret is a shared secret between the server and the client | ||
jsonWebSignature.setDoKeyValidation(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, when the user wants to sign using symmetric keys, we are signing using the client secret. However, I am not sure what to do when they use JWT as client credentials instead of client secret.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PrarthonaPaul Can they use JWT as a client credential? Can you please describe the background for the situation you are asking about?
in the proposal you mentioned:
In order to sign the jwt using an algorithm other than none, the user must specify the KeyPair used.
So I thought the keypair can be used in all situations for signing but you might be asking about something else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, sorry.
According to this doc: https://www.keycloak.org/docs/latest/securing_apps/#_client_authentication_adapter
we can either set up the client credentials to be just the client secret, which is a just a hash/SHA (like 19666a4f-32dd-4049-b082-684c74115f28).
But you can also configure it using a JWT. But it is not related to the request RFE.
This is what the options are for specifying the client credentials:
Now the reason I am using the client secret to sign a JWT for my RFE is because as we found out HS keys are symmetric. And from what I have seen instead of creating a certificate, we create a secret that is shared between the client. For Keycloak, the client secret is something that is shared between the client and the server.
But what I am wondering is what happens when the user configures the client credentials as a JWT or X509 certificate?
aa4ac31
to
58fd4a6
Compare
58fd4a6
to
0bc8938
Compare
@@ -156,7 +156,7 @@ protected JwtClaims createRequestToken(String clientId, String tokenUrl) { | |||
return jwtClaims; | |||
} | |||
|
|||
private static KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType) { | |||
protected static KeyPair loadKeyPairFromKeyStore(String keyStoreFile, String storePassword, String keyPassword, String keyAlias, String keyStoreType) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is a generic helper method that will also be used in OidcRequestAuthenticator, it would be better to move this method to either an existing utility class or introduce a new utility class and include this method there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good.
Does this class: https://github.com/wildfly-security/wildfly-elytron/blob/2.x/http/oidc/src/main/java/org/wildfly/security/http/oidc/ClientCredentialsProviderUtils.java look like a good one to move this function to?
If not, then we can create another utility class called JWTClientCredentialsProviderUtils.java
or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the method will also be used for signing the authentication request in addition to being used for client credentials handling, I think we could create another utility class but try to give it a more generic name (e.g., JWTSigningUtils or something along those lines).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay! Sounds good! Thanks :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is done!
@@ -52,10 +52,14 @@ public class Oidc { | |||
public static final String TEXT_CONTENT_TYPE = "text/*"; | |||
public static final String DISCOVERY_PATH = ".well-known/openid-configuration"; | |||
public static final String KEYCLOAK_REALMS_PATH = "realms/"; | |||
public static final String KEYSTORE_PASS = "password"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this something that's used for tests? It shouldn't be added to the constants class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved relevant constants to KeycloakConfiguration class.
@@ -52,10 +52,14 @@ public class Oidc { | |||
public static final String TEXT_CONTENT_TYPE = "text/*"; | |||
public static final String DISCOVERY_PATH = ".well-known/openid-configuration"; | |||
public static final String KEYCLOAK_REALMS_PATH = "realms/"; | |||
public static final String KEYSTORE_PASS = "password"; | |||
public static final String PKCS12_KEYSTORE_TYPE = "PKCS12"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, this looks like something that's only needed for tests, it shouldn't be in the Oidc constants class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to keycloakConfiguration class
public static final String JSON_CONFIG_CONTEXT_PARAM = "org.wildfly.security.http.oidc.json.config"; | ||
static final String ACCOUNT_PATH = "account"; | ||
public static final String CLIENTS_MANAGEMENT_REGISTER_NODE_PATH = "clients-managements/register-node"; | ||
public static final String CLIENTS_MANAGEMENT_UNREGISTER_NODE_PATH = "clients-managements/unregister-node"; | ||
public static final String ADMIN_CONSOLE_PATH = "admin/master/console/#"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check all the new constants introduced in this class, it looks like these were meant for tests purposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
@@ -116,6 +125,35 @@ public class Oidc { | |||
public static final String X_REQUESTED_WITH = "X-Requested-With"; | |||
public static final String XML_HTTP_REQUEST = "XMLHttpRequest"; | |||
|
|||
/* Accepted Request Object Signing Algorithms for KeyCloak*/ | |||
public static final String NONE = "none"; | |||
public static final String RS_256 = "RS256"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that this class already contains some constants with similar names and also makes use of the AlgorithmIdentifiers class.
These newly added constants appear to be specific to the Keycloak OpenID provider.
Are these really needed?
Can we get the allowed values from discovery?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
I am using AlgorithmIdentifiers class and throwing an exception if the algorithm is not supported.
public static final String PS_512 = "PS512"; | ||
|
||
/* Accepted Request Object Encrypting Algorithms for KeyCloak*/ | ||
public static final String RSA_OAEP = "RSA-OAEP"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
public static final String RSA1_5 = "RSA1_5"; | ||
|
||
/* Accepted Request Object Encryption Methods for KeyCloak*/ | ||
public static final String A256GCM = "A256GCM"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, can we get these accepted values through discovery instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like most of these, I use for testing, and some of them I don't use at all.
So, I can remove/move those to a test Class, like KeycloakConfiguration
. For some of the others, I am using them in the actual implementation. So, I can replace them using AlgorithmIdentifiers.
I can get them using Discovery and I think I do get them. But I don't think I use them yet.
@@ -223,6 +249,15 @@ protected void resolveUrls() { | |||
tokenUrl = config.getTokenEndpoint(); | |||
logoutUrl = config.getLogoutEndpoint(); | |||
jwksUrl = config.getJwksUri(); | |||
authorizationEndpoint = config.getAuthorizationEndpoint(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which endpoint is this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see something that corresponds to this added in OidcProviderMetadata, is this necessary? Or is it just the pushedAuthorizationRequestEndpoint that's needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I do see authorization_endpoint already referenced in the existing OidcProviderMetadata code. But just to understand better, is the authorizationEndpoint variable that's being introduced here used anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has this endpoint: http://localhost:8080/realms/myrealm/protocol/openid-connect/auth/device
I don't think I use it tho. So I can get rid of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
requestObjectEncryptionEncValuesSupported = config.getRequestObjectEncryptionEncValuesSupported(); | ||
requestObjectEncryptionAlgValuesSupported = config.getRequestObjectEncryptionAlgValuesSupported(); | ||
requestUriParameterSupported = config.getRequestUriParameterSupported(); | ||
realmKeySet = createrealmKeySet(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need to create the realm key set here. It would be better to do this when we know we actually need to make use of it (similar to JWKPublicKeyLocator where we use the jwks url when we know we need to).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to OidcPublicKeyExtractor
@@ -237,6 +272,26 @@ protected void resolveUrls() { | |||
} | |||
} | |||
|
|||
private JsonWebKeySet createrealmKeySet() throws Exception{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"realm" is terminology specific to Keycloak so I don't think we should use it in the method name here.
This method is meant to obtain the encryption keys from the OpenID provider, right? We should rename this method to reflect that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed the function from this class and moved it to a utility class. New function is called extractPublicKeySet
@@ -237,6 +272,26 @@ protected void resolveUrls() { | |||
} | |||
} | |||
|
|||
private JsonWebKeySet createrealmKeySet() throws Exception{ | |||
HttpGet request = new HttpGet(jwksUrl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make use of the Oidc.sendJsonHttpRequest method here to simplify the logic below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried doing this and kept getting a class mismatch for the JsonSerialization.readValue()
function.
I tried this for the JsonWebKeySet, String, and StringBuilder classes.
When I was initially writing this function, I was also trying to use JsonSerialization.readValue()
and did not succeed. Which is why I had to do this workaround.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be an example in JWKPublicKeyLocator where we call sendJsonHttpRequest and store the result in a JsonWebKeySet. Did you take a look there to see how that differs from what you were trying to do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what the difference is.
The JWKPublicKeyLocator class uses org.wildfly.security.jose.jwk.JsonWebKeySet and I am using the Jose4j one, which is why the parsing failed before.
I have switched it to the wildfly.security one now and it works.
Thank you!
return authenticationRequestFormat; | ||
} | ||
|
||
public void setAuthenticationRequestFormat(String requestObjectType ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/requestObjectType/authenticationRequestFormat ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed!
return requestSignatureAlgorithm; | ||
} | ||
|
||
public void setRequestSignatureAlgorithm(String algorithm) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/algorithm/requestSignatureAlgorithm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
return requestEncryptAlgorithm; | ||
} | ||
|
||
public void setRequestEncryptAlgorithm(String algorithm) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/algorithm/requestEncryptionAlgorithm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed!
return requestEncryptEncValue; | ||
} | ||
|
||
public void setRequestEncryptEncValue (String enc) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra white space before bracket
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
this.requestSignatureAlgorithm = algorithm; | ||
} | ||
|
||
public String getRequestEncryptAlgorithm() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be consistent with the naming pattern for the signing case, there we used getRequestObjectSigningAlgValuesSupported so we should follow a similar pattern here and below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed!
this.requestEncryptEncValue = enc; | ||
} | ||
|
||
public String getRealmKey () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't use "realm" here. We should rename this to better explain what this returns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't using these functions, so I removed anything related to realmKey that I added.
http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfiguration.java
Show resolved
Hide resolved
this.clientKeyAlias = alias; | ||
} | ||
|
||
public JsonWebKeySet getrealmKeySet() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that method names should use camel case, i.e., style wise, getrealm should be getRealm.
However, we should rename this to not mention realm as described in comments above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to utility class and renamed.
redirectUriBuilder.addParameter(REDIRECT_URI, redirectUri) | ||
.addParameter(STATE, state) | ||
.addParameters(forwardedQueryParams); | ||
log.info("The OpenID provider does not support the request parameter. Sending the request using OAuth2 format."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should make use of ElytronMessages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
6bf8688
to
62ba916
Compare
62ba916
to
cd4478d
Compare
968c2e5
to
634191c
Compare
@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.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/The signature algorithm/request object signature algorithm
@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.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/The encryption algorithm/request object encryption algorithm
@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.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/The content encryption algorithm/The request object content encryption algorithm
@Message(id = 23060, value = "The content encryption algorithm specified is not supported by the OpenID Provider.") | ||
IOException invalidRequestObjectContentEncryptionAlgorithm(); | ||
|
||
@LogMessage(level = INFO) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use WARN here instead of INFO.
* | ||
* @author <a href="mailto:prpaul@redhat.com">Prarthona Paul</a> | ||
*/ | ||
public interface OidcPublicKeyExtractor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks similar to the PublicKeyLocator
interface. Can we make use of the existing interface instead?
* @author <a href="mailto:prpaul@redhat.com">Prarthona Paul</a> | ||
*/ | ||
|
||
public class JWTSigningUtils implements JWTSigning{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the JWTSignging interface is needed. We can just use the utility class.
/** | ||
* Get the string value for this referral mode. | ||
* | ||
* @return the string value for this referral mode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely just a copy/paste issue but "referral mode" needs to be updated.
} else { | ||
oidcClientConfiguration.setRequestSignatureAlgorithm(NONE); | ||
} | ||
if (oidcJsonConfiguration.getRequestEncryptAlgorithm() != null && oidcJsonConfiguration.getRequestContentEncryptionMethod() != null) { //both are required to encrypt the request object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to throw an IllegalArgumentException if only one is specified if that's invalid configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we know that we'll need to encrypt the request object, maybe we can set the public key locator for that here on the oidcClientConfiguration
(e.g., oidcClientConfiguration.setEncPublicKeyLocator
or something like that) similar to the way we set the public key locator for the SIG case.
this.requestObjectSigningKeystoreFile = keyStoreFile; | ||
} | ||
|
||
public String getRequestObjectSigningKeyStorePassword() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be consistent with Keystore or KeyStore in the method names in this file.
} | ||
|
||
@Override | ||
public String getRequestObjectSigningKeyStorePassword() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be consistent with Keystore vs KeyStore in the method names in this file.
* | ||
* @author <a href="mailto:prpaul@redhat.com">Prarthona Paul</a> | ||
* */ | ||
public class JWKPublicKeySetExtractor implements OidcPublicKeyExtractor { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be a non-public class that implements PublicKeyLocator
, similar to JWKPublicKeyLocator
but it would be used to obtain the public key for JWK.Use.ENC
instead of JWK.Use.SIG
. This should also cache the key like JWKPublicKeyLocator
does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have followed the PublicKeyLocator class to implement caching.
Please let me know if it makes sense.
* @author <a href="mailto:prpaul@redhat.com">Prarthona Paul</a> | ||
*/ | ||
|
||
public interface JWTSigning { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need this interface.
String[] unsupportedAttributes = unsupportedAttributesParameter.split(" "); | ||
for (String attributeName : unsupportedAttributes) { | ||
switch(attributeName) { | ||
case AUTHENTICATION_REQUEST_FORMAT: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the scope RFE, we shouldn't need to hardcode information about the unsupported attributes for WildFly. We'll need to add the handling for unsupported attributes in the elytron-oidc-client
subsystem.
protected String authenticationRequestFormat; | ||
protected String requestSignatureAlgorithm; | ||
protected String requestEncryptAlgorithm; | ||
protected String requestContentEncryptionMethod; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be consistent with the use of request
vs requestObject
. I think using requestObject
makes sense since that matches the actual attribute names too.
protected String authenticationRequestFormat; | ||
|
||
@JsonProperty("request-object-signing-algorithm") | ||
protected String requestSignatureAlgorithm; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requestObjectSignatureAlgorithm
protected String requestSignatureAlgorithm; | ||
|
||
@JsonProperty("request-object-encryption-algorithm") | ||
protected String requestEncryptAlgorithm; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requestObjectEncryptionAlgorithm
protected String requestEncryptAlgorithm; | ||
|
||
@JsonProperty("request-object-content-encryption-algorithm") | ||
protected String requestContentEncryptionMethod; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requestObjectContentEncryptionAlgorithm
@@ -62,8 +63,16 @@ public class OidcJsonConfiguration { | |||
protected String clientKeystore; | |||
@JsonProperty("client-keystore-password") | |||
protected String clientKeystorePassword; | |||
@JsonProperty("client-key-password") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this removed?
"allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password", | ||
"client-keystore", "client-keystore-password", "client-key-password", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like client-key-password was removed?
return pushedAuthorizationRequestEndpoint; | ||
} | ||
|
||
public void setPushedAuthorizationRequestEndpoint (String url) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just minor, extra space before the (
@@ -66,7 +67,7 @@ public void contextInitialized(ServletContextEvent sce) { | |||
if (is == null) { | |||
oidcClientConfiguration = new OidcClientConfiguration(); | |||
} else { | |||
oidcClientConfiguration = OidcClientConfigurationBuilder.build(is); | |||
oidcClientConfiguration = OidcClientConfigurationBuilder.buildWithoutUnsupportedAttributes(is, servletContext.getInitParameter(JSON_CONFIG_UNSUPPORTED_ATTRIBUTE_PARAM)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as on the other PR:
https://github.com/wildfly-security/wildfly-elytron/pull/1925/files#r1532368580
} | ||
} | ||
|
||
public KeyPair getkeyPair() throws IOException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be private static. The deployment
can be passed as a parameter.
jsonEncryption.setAlgorithmConstraints(new AlgorithmConstraints(AlgorithmConstraints.ConstraintType.PERMIT, deployment.getRequestEncryptAlgorithm(), deployment.getRequestContentEncryptionMethod())); | ||
jsonEncryption.setAlgorithmHeaderValue(deployment.getRequestEncryptAlgorithm()); | ||
jsonEncryption.setEncryptionMethodHeaderParameter(deployment.getRequestContentEncryptionMethod()); | ||
JWK[] jwkList = new JWKPublicKeySetExtractor().extractPublicKeySet(deployment).getKeys(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of needing to use new JWKPublicKeySetExtractor()
, we can get the public key locator to use from the oidcClientConfiguration
(e.g., oidcClientConfiguration.getEncPublicKeyLocator
) and then make use of that to be obtain the public key.
jsonEncryption.setEncryptionMethodHeaderParameter(deployment.getRequestContentEncryptionMethod()); | ||
JWK[] jwkList = new JWKPublicKeySetExtractor().extractPublicKeySet(deployment).getKeys(); | ||
for (JWK jwk : jwkList) { | ||
if (jwk.getPublicKeyUse().equals("enc")) { //JWTs are to be encrypted with public keys shared by the OpenID provider and decrypted by the private key they hold |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the logic of finding the "enc" public key would be part of the locator class.
return redirectUriBuilder.build().toString(); | ||
} catch (URISyntaxException e) { | ||
throw log.unableToCreateRedirectResponse(e); | ||
} catch (IOException | JoseException | InvalidJwtException e) { | ||
throw new RuntimeException(e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should add a new message to ElytronMessages for this (there should be other examples there for RuntimeExceptions that wrap another exception).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have changed this to be a nested try-catch, where the inner try catch surrounds createRequestWithRequestParameter(REQUEST, redirectUriBuilder, redirectUri, state, forwardedQueryParams);
However, log.unableToCreateRequestWithRequestParameter()
throws a runtime exception, since it can either be an IO exception, or a joseException or InvalidJwtException.
Alternatively, I could throw these exceptions separately, but earlier in the stack of function calls.
@@ -0,0 +1,44 @@ | |||
/* | |||
* JBoss, Home of Professional Open Source. | |||
* Copyright 2020 Red Hat, Inc., and individual contributors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2024?
df298ec
to
6ad38e0
Compare
…quest should include request and request_uri parameters
a764c3f
to
ab5f2a1
Compare
https://issues.redhat.com/browse/ELY-2584
Analysis doc: wildfly/wildfly-proposals#532
Relevant discussion page: