Unable to validate token: Couldn't retrieve remote JWK set - oauth-2.0

I'm setting up an authentication method on Nexus Hybrid Access Gateway based on OpenID Connect, using ADFS as an identity provider.
The goal is to access Nexus Hybrid Access Gateway using the OpenID Connect authentication method.
When configuring OpenID Connect on Nexus HAG I specified the following informations for the Identity Provider :
- Cliend ID : 3b6fc4cc7463......
- Client Secret : 812e4167....
- Discovery EndPoint : https://example.com/adfs/.well-known/openid-configuration
When I try to log in to Nexus HAG portail using the OpenID Connect authentication method, i'm redirected to "https://example.com/adfs/ls/idpinitatedsignon" page to specify user credentials. ADFS is able to verify my credentials, but on my server (Nexus) I keep having this message:
AUTHENTICATION_MECHANISM:[ 14 ] MECHANISM_MESSAGE:[ Unable to validate
token: Couldn't retrieve remote JWK set: Connection reset ]
RADIUS_REJECT_MESSAGE:[ Unable to validate token: Couldn't retrieve
remote JWK set: Connection reset ]
Any help will be much appreciated.
Thanks.

Related

Keycloak token verification fails when the backend is running in a Docker container

I am in the early stages of building my web application. I intend to use Keycloak as the identity provider to secure the backend. On my local machine, I am running both Keycloak and my backend as docker containers but on different networks, since eventually in production, I would like to have the authentication server running Keycloak running separately from the backend e.g account.example.com and api.example.com respectively
Locally, my Keycloak container can be accessed via the base URL http://localhost:8080/auth and the backend via http://test.localhost:8000/
I have created a client in the Keycloak realm whose access type is confidential. I am generating the token using the authorization code grant type.
Each REST API endpoint on the backend would therefore verify the token passed to the authorization header and then call the Keycloak server to verify the token before processing the request.
The issue that I am currently experiencing is that the token verification fails with the response
{"error":"invalid_token","error_description":"Token verification failed"}'
After investigation, apparently, it's because I am calling the Keycloak server from the backend API container. If I generate the token using curl within the backend docker container, the token I receive is being verified fine, but a token generated outside the container is not.
I am using python-keycloak as a wrapper for Keycloak REST API
from keycloak import KeycloakOpenID
self._keycloak = KeycloakOpenID(
server_url='http://host.docker.internal:8080/auth/',
realm_name='myrealm',
client_id='myclient',
client_secret_key='mysecret,
)
if "HTTP_AUTHORIZATION" not in request.META:
return JsonResponse(
{"detail": NotAuthenticated.default_detail},
status=NotAuthenticated.status_code,
)
auth_header = request.META.get("HTTP_AUTHORIZATION").split()
token = auth_header[1] if len(auth_header) == 2 else auth_header[0]
try:
self.keycloak.userinfo(token)
except KeycloakInvalidTokenError as e:
# print(e)
return JsonResponse(
{"detail": AuthenticationFailed.default_detail},
status=AuthenticationFailed.status_code,
)
How do I resolve this and have token verification working on my local machine
Your token is invalid, because the issuer (iss) in the token does not match the issuer that is expected by your backend service.
Your backend (or an adapter/framework within your backend) will use OIDC discovery protocol to determine the expected issuer. For this, it will call https://keycloak-container-name/auth/realms/<your-realm>/.well-known/openid-configuration. This will return metadata like this:
{
"issuer":"https://keycloak-container-name/auth/realms/<your-realm>",
...
}
Keycloak will determine the host part of the issuer (keycloak-container-name in this case) based on the request. So, if your backend queries the discovery endpoint wiht keycloak-container-name from within the docker network, the host part will be your-container-name. Your backend will expect the issuer to be https://keycloak-container-name/auth/realms/<your-realm> in this case.
Now, if you want to query a token from your frontend, your frontend will send the request to http://localhost:8080/auth/.... Since the issuer will be determined based on the request, the issuer in that token will be https://localhost:8080/auth/realms/<your-realm> in this case.
This does not match the expected issuer https://keycloak-container-name/auth/realms/<your-realm> and therefore the token will be rejected as invalid.
You can also verify this by calling the OIDC discovery endpoint via http://localhost:8080/auth/realms/<your-realm>/.well-known/openid-configuration. You will get a response like this:
{
"issuer":"http://localhost:8080/auth/realms/<your-realm>",
...
}
To fix this you can set the Frontend URL in your realm to http://localhost:8080/auth. With this setting the issuer will no longer be determined in the request, but will be fixed http://localhost:8080/auth/realms/<your-realm>.
You can check this from within your backend container by issuing a request to https://keycloak-container-name/auth/realms/<your-realm>/.well-known/openid-configuration. This will return metadata like this now:
{
"issuer":"http://localhost:8080/auth/realms/<your-realm>",
...
}
If you do not want to configure this for every realm seperately, you may instead configure the default hostname provider server-wide.
Problem is with the issuer of the token. Issuer of your token from the postman is http://localhost:8080/..., but backend is configured to accept only issuer http://host.docker.internal:8080/.... It is a best practise to use the same protocol:domain[:port] for IdP (Keycloak in your case) everywhere e.g. https://keycloak.domain.com, otherwise you will have this kind of problems.

Spring Boot + Security OAuth2.0 Client with Custom Provider

I am creating a OAuth2.0 client for a custom OAuth2 provider in Spring Boot + Security (version 5) application.
Below is the application.properties which has all the configuration and there is no additional configuration class in my project.
spring.security.oauth2.client.registration.xxxxxxxxx.client-id=XXXXXXXXXX
spring.security.oauth2.client.registration.xxxxxxxxx.client-secret=XXXXXXXXXX
spring.security.oauth2.client.registration.xxxxxxxxx.scope=openid
spring.security.oauth2.client.registration.xxxxxxxxx.redirect-uri-template=http://localhost:8080/login/oauth2/code/xxxxxxxxx
spring.security.oauth2.client.registration.xxxxxxxxx.client-name=xxxxxxxxx
spring.security.oauth2.client.registration.xxxxxxxxx.provider=xxxxxxxxx
spring.security.oauth2.client.registration.xxxxxxxxx.client-authentication-method=basic
spring.security.oauth2.client.registration.xxxxxxxxx.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.xxxxxxxxx.authorization-uri=https://api.xxxxxxxxx.com/authorize
spring.security.oauth2.client.provider.xxxxxxxxx.token-uri=https://api.xxxxxxxxx.com/token
spring.security.oauth2.client.provider.xxxxxxxxx.user-info-uri=https://api.xxxxxxxxx.com/userinfo?schema=openid
spring.security.oauth2.client.provider.xxxxxxxxx.user-name-attribute=name
spring.security.oauth2.client.provider.xxxxxxxxx.user-info-authentication-method=header
When i hit http://localhost:8080/ it redirects properly to provider's login page and after successful login it redirects back to my application.
Now the problem is when it redirects then it shows below error message.
I have googled for this error but didn't get any proper answer. Also, the OAuth2 provider didn't share such URL.
After research I came to know that i need to set below property. Should it be provided by Auth Provider?
spring.security.oauth2.client.provider.pepstores.jwk-set-uri
What exactly I am missing here in configuration?
Finally, the problem is solved. I just need to configure the jwk URI which should be provided by the Auth provider.
Below the final configuration for customer Auth Provider.
spring.security.oauth2.client.registration.xxxxxxxxx.client-id=XXXXXXXXXX
spring.security.oauth2.client.registration.xxxxxxxxx.client-secret=XXXXXXXXXX
spring.security.oauth2.client.registration.xxxxxxxxx.scope=openid
spring.security.oauth2.client.registration.xxxxxxxxx.redirect-uri-template=http://localhost:8080/login/oauth2/code/xxxxxxxxx
spring.security.oauth2.client.registration.xxxxxxxxx.client-name=xxxxxxxxx
spring.security.oauth2.client.registration.xxxxxxxxx.provider=xxxxxxxxx
spring.security.oauth2.client.registration.xxxxxxxxx.client-authentication-method=basic
spring.security.oauth2.client.registration.xxxxxxxxx.authorization-grant-type=authorization_code
spring.security.oauth2.client.provider.xxxxxxxxx.authorization-uri=https://api.xxxxxxxxx.com/authorize
spring.security.oauth2.client.provider.xxxxxxxxx.token-uri=https://api.xxxxxxxxx.com/token
spring.security.oauth2.client.provider.xxxxxxxxx.user-info-uri=https://api.xxxxxxxxx.com/userinfo?schema=openid
spring.security.oauth2.client.provider.xxxxxxxxx.user-name-attribute=name
spring.security.oauth2.client.provider.xxxxxxxxx.user-info-authentication-method=header
spring.security.oauth2.client.provider.xxxxxxxxx.jwk-set-uri=https://api.xxxxxxxxx.com/jwks
Thanks
When you receive JWT in client application, you need to verify the signature of JWT. To verify the signature you need public key of Auth provider. As per OAuth specifications, Auth provider can expose the public key through a URI and client can use this URI to get the public key to validate the JWT. This is what is missing in your configuration.

Spring Security SAML with wso2 IS

I am trying to integrate(SSO) multiple service providers using spring security and wso2 identity server 5.1.0 I have integrated spring security SAML sample with Wso2 IS as according to the blog for only one service provider and its running perfectly fine, but I am not able to do SSO for multiple service providers. I have checked everything but no luck.
Please find below what I think it should be but I am not sure how to achieve this.
WSO2 IS : created a service provider with unique SAML issuer id(ex. spring-security),which will be used from different service providers for SSO.
SP1 : Service provider should send Authn request having issue id(spring-security) and a assertion consumer url(ex. localhost:8080/...).
SP2 : Service provider should send Authn request having issue id(spring-security) and a assertion consumer url(ex. localhost:8181/...).
Issuer in Authn Request :
http://localhost:8080/spring-security-saml2-sample/saml/metadata
Even I am not sure how this issuer is being generated.
Please help.
You have to use different and unique entity ids for each service provider. And at Identity Server you need to create multiple service providers (2 in your case) accordingly in order to get SSO (and SLO) working.
So let's say you get the entity ids changed for two SPs as spring-security-1 and spring-security-2. You will need to create 2 service providers at IS as below.
SP1 -> issuer : spring-security-1 , ACS url : localhost:8080/...
SP2 -> issuer : spring-security-2 , ACS url : localhost:8081/...

WebSphere Liberty Profile OIDC Client URL

I am trying to use the WebSphere Liberty Profile OIDC Client feature. I have the feature installed and configured, but I am confused about what URL I should be using to connect to it. In the WLP Knowledge Center, it shows an example like this:
https://server.example.com:443/oidc/endpoint/PROVIDER_NAME/authorize
But when my WLP server comes up, I see the following URL in the log:
com.ibm.ws.webcontainer.osgi.DynamicVirtualHost I addWebApplication SRVE0250I: Web Module OpenID Connect Client Redirect Servlet has been bound to default_host.
com.ibm.ws.http.internal.VirtualHostImpl A CWWKT0016I: Web application available (default_host): http://ibm669-r9v0dvb:11080/oidcclient/
I don't know whether to use 'oidcclient' (probably) or 'oidc'. I also don't know what to put as the PROVIDER_NAME. I tried using the ID of my OIDCClient:
<openidConnectClient id="oidcRP"
clientId="${oauth.client.id}"
clientSecret="${oauth.client.secret}"
authorizationEndpointUrl="${oauth.authorize.endpoint}"
tokenEndpointUrl="${oauth.token.endpoint}"
httpsRequired="false"
redirectToRPHostAndPort="https://myhost.com:443">
I tried connecting with this, but it's not finding it:
http://ibm669-r9v0dvb:11080/oidcclient/endpoint/oidcRP/authorize?scope=openid&response_type=code&client_id=XXX&redirect_uri=https://myhost.com:443
com.ibm.ws.webcontainer.extension.DefaultExtensionProcessor W handleRequest SRVE0190E: File not found: /endpoint/oidcRP/authorize
Can anyone tell me what URL I should be using to connect to the client?
The Liberty openidConnectClient feature enables Liberty as a client to openid connect provider. The configuration parameters inside openidConnectClient are information about openidConnectProvider, for example, the openidConnect provider's authorization endpoint and token endpoint.
What is your openid connect provider? Liberty also can be configured as openid Connect provider. If you also want to use Liberty as openid connect provider, you can create another Liberty instance and enable openidConnectProvider feature.

Javamail OAuth authentication failed when connecting to Exchange imap using OAuth token

I'm trying to connect to Exchange using Javamail and OAuth. I'm using Javamail 1.5.3 and I referred to this.
1) The exchange account that I'm trying to connect to is within an org domain. I know that my OAuth token is valid since I'm able to make a Rest api request to https://outlook.office.com/api/v2.0/me to get the user profile using the token. My code looks like this -
Properties props = new Properties();
props.put("mail.imap.ssl.enable", "true);
props.put("mail.imap.sasl.enable", "true");
props.put("mail.imap.sasl.mechanisms", "XOAUTH2");
props.put("mail.imap.auth.login.disable", "true");
props.put("mail.imap.auth.plain.disable", "true");
Session session = Session.getInstance(props);
Store store = session.getStore("imap");
store.connect("imap-mail.outlook.com", "xxx#org.com", OAUTH_TOKEN);
I get (javax.mail.AuthenticationFailedException) javax.mail.AuthenticationFailedException: [AUTHENTICATIONFAILED] OAuth authentication failed
2) When I connect to an xxx#outlook.com account, I get 500:Internal Server Error and I'm not able to make the api request above to fetch the user profile using the OAuth token I received.

Resources