Validate JWT token with com.nimbusds.jose and a public certificate url from Azure AD - spring-security

I'm using a com.nimbusds.jose implementation in order to validate a token by retrieving the public key which was used to sign the JWT from Microsoft authorization server configuration (property jwks_uri). When I'm trying to validate the token by using the code written bellow, I'm getting:
com.nimbusds.jose.RemoteKeySourceException: Couldn't retrieve remote JWK set: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target.
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
try {
ConfigurableJWTProcessor jwtProcessor = new DefaultJWTProcessor();
JWKSource keySource = null;
try {
ResourceRetriever jwkRetriever = new DefaultResourceRetriever(100000, 100000);
JWKSetCache jwkSetCache = new DefaultJWKSetCache(1440,
1430, TimeUnit.MINUTES);
keySource = new RemoteJWKSet(new URL(
"https://login.windows.net/36799f34-92fd-4612-8473-80173f2406e8/discovery/v2.0/keys"),jwkRetriever,jwkSetCache);
} catch (MalformedURLException e) {
e.printStackTrace();
}
JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256;
JWSKeySelector keySelector = new JWSVerificationKeySelector(expectedJWSAlg,keySource);
jwtProcessor.setJWSKeySelector(keySelector);
JWTClaimsSet claimsSet = null;
SecurityContext ctx = null; // optional context parameter, not required here
try {
claimsSet = jwtProcessor.process(token, ctx);
} catch (ParseException e) {
e.printStackTrace();
} catch (BadJOSEException e) {
e.printStackTrace();
} catch (JOSEException e) {
e.printStackTrace();
}
I've added the certificates in the truststore. See bellow the configuration from Spring application.properties file:
trust.store=myapp_dev.p12
trust.store.password=changeit
What I'm doing wrong? Can you please help me?
Regards,

Related

"invalid_client" in Spring Security when using private_key_jwt instead of client_secret_basic

I have tried to switch from client_secret_basic to private_key_jwt, but I'm getting the following error when I'm sent back from the auth provider:
[invalid_client] Client authentication failed. No client authentication included
It's not a Spring Boot app, but this is what I have done so far:
private ClientRegistration idPortenClientRegistration() {
return ClientRegistrations
.fromIssuerLocation("the endpoint")
.clientId("the client id")
.registrationId("idporten")
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("the redirect url")
.scope(Arrays.asList("the scopes"))
.userNameAttributeName(IdTokenClaimNames.SUB)
.clientName("idporten")
.clientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT);
.build();
}
My SecurityConfig.class:
http.oauth2Client(oauth2 -> oauth2
.authorizationCodeGrant(codeGrant -> codeGrant
.accessTokenResponseClient(accessTokenResponseClient())));
[…]
private DefaultAuthorizationCodeTokenResponseClient accessTokenResponseClient() {
OAuth2AuthorizationCodeGrantRequestEntityConverter requestEntityConverter = new OAuth2AuthorizationCodeGrantRequestEntityConverter();
requestEntityConverter.addParametersConverter(
new NimbusJwtClientAuthenticationParametersConverter<>(jwkResolver));
DefaultAuthorizationCodeTokenResponseClient tokenResponseClient = new DefaultAuthorizationCodeTokenResponseClient();
tokenResponseClient.setRequestEntityConverter(requestEntityConverter);
return tokenResponseClient;
}
private Function<ClientRegistration, JWK> jwkResolver = (clientRegistration) -> {
if (clientRegistration.getClientAuthenticationMethod().equals(ClientAuthenticationMethod.PRIVATE_KEY_JWT)) {
JKSKeyManager keyManager = getApplicationContext().getBean("keyManager", JKSKeyManager.class);
try {
RSAPublicKey publicKey = (RSAPublicKey) keyManager.getPublicKey("idporten1");
KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyManager.getKeyStore()
.getEntry("idporten1", new KeyStore.PasswordProtection(keyEntryPassword1.toCharArray()));
RSAPrivateKey privateKey = (RSAPrivateKey) pkEntry.getPrivateKey();
return new RSAKey.Builder(publicKey).privateKey(privateKey).keyID(UUID.randomUUID().toString()).build();
} catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) {
logger.error("Failed to configure jwkResolver: " + e.getMessage(), e);
}
}
return null;
};
As mentioned, I'm successfully redirected to the auth provider, but getting the error described above when I'm sent back to the application. I have also tried to log accessTokenResponseClient() and jwkResolver. The former method gets called just before the error occurs, but nothing gets logged from the latter.
Some documentation from the provider:
https://docs.digdir.no/oidc_protocol_token.html
https://oidc-ver2.difi.no/idporten-oidc-provider/.well-known/openid-configuration

How to handle incorrect credentials with google oauth2 Installed Application code flow

I'm implementing the authorization code flow for Installed Application.
Code is similar to snippet below:
public static void main(String[] args) {
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport,
JSON_FACTORY,
IA_CLIENT,
IA_SECRET,
Collections.singleton(DriveScopes.DRIVE)).setDataStoreFactory(dataStoreFactory)
.build();
Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
drive = new Drive.Builder(httpTransport, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();
System.out.println(drive.about());
return;
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (Throwable t) {
t.printStackTrace();
}
System.exit(1);
}
Everything is working fine except in the case when I provide an invalid client_id. (I've the same issue if I use a json file and alter its content).
I get this get of error message from Google server:
401. That’s an error.
Error: invalid_client
The OAuth client was not found.
Request Details
client_id=573900000-hsoobsdsstem84tg8br4pmdsds.apps.googleusercontent.com
redirect_uri=http://localhost:40441/Callback
response_type=code
scope=https://www.googleapis.com/auth/drive
... and the callback server never receives any feedback. So, the application
is still running endlessly.
I've looked at the LocalServerReceiver class but could find any way to provide a
timeout or any potential solution.
What's the cleanest way to handle this case ?

How to get access_token of Exact Online API using apache OAuth 2.0

We are trying to use Exact Online API. It is using Apache OAuth 2.0 framework. For that we followed the below document.
https://developers.exactonline.com/#OAuth_Tutorial.html%3FTocPath%3DAuthentication%7C_____2
I successfully able to get the authorization code but failing to get the access_token with exception like below.
OAuthProblemException{error='invalid_request', description='Missing parameters: access_token', uri='null', state='null', scope='null', redirectUri='null', responseStatus=0, parameters={}}
My code is like this.
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
PrintWriter out = response.getWriter();
try {
OAuthAuthzResponse oar = OAuthAuthzResponse.oauthCodeAuthzResponse(request);
String code = oar.getCode();
OAuthClientRequest oAuthrequest = OAuthClientRequest
.tokenLocation("https://start.exactonline.co.uk/api/oauth2/token")
.setGrantType(GrantType.AUTHORIZATION_CODE)
.setClientId("my client id")
.setClientSecret("my client secret")
.setRedirectURI("http://localhost:8080/SampleServlet/AuthServlet")
.setCode(code)
.buildBodyMessage();
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
GitHubTokenResponse oAuthResponse = oAuthClient.accessToken(oAuthrequest, "POST",GitHubTokenResponse.class);
out.println("Access Token = " + oAuthResponse.getAccessToken());
} catch (OAuthSystemException ex) {
Logger.getLogger(AuthServlet.class.getName()).log(Level.SEVERE, null, ex);
} catch (OAuthProblemException ex) {
Logger.getLogger(AuthServlet.class.getName()).log(Level.SEVERE, null, ex);
} finally {
out.close();
}
}
Can some one please help me to sort this out.
Finally i resolved this issue with a simple change. The problem is with the line
GitHubTokenResponse oAuthResponse = oAuthClient.accessToken(oAuthrequest, "POST",GitHubTokenResponse.class);
Instead of this we have to use either of the below lines to get the access token properly.
OAuthJSONAccessTokenResponse oAuthResponse = oAuthClient.accessToken(oAuthrequest, OAuth.HttpMethod.POST);
(Or)
OAuthAccessTokenResponse oAuthResponse =oAuthClient.accessToken(oAuthrequest,OAuth.HttpMethod.POST);

Cant connect to survey monkey API

I am trying to connect to the survey monekey API with this code, which is not working. It says "Invalid API key" even though I got the API from the API console.
public void fetch() {
String url = "https://api.surveymonkey.net/v2/surveys/get_survey_list?api_key=" + apiKey;
System.out.println("request being sent");
System.out.println(url);
JSONObject obj = new JSONObject();
try {
// byte[] postDataBytes = obj.toJSONString().getBytes("UTF-8");
URL ourl = new URL(url.toString());
HttpURLConnection conn = (HttpURLConnection) ourl.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "bearer " + accessToken);
conn.setRequestProperty("Content-Type", "application/json");
conn.getRequestProperty(obj.toString().getBytes("UTF-8").toString());
int k = conn.getResponseCode();
System.out.println("The response code received is " + k);
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String output;
System.out.println("Output from Server .... \n");
output = br.readLine();
System.out.println(output);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Here's the error:
request being sent
https://api.surveymonkey.net/v2/surveys/get_survey_list?api_key=---API-KEY----
The response code received is 200
Output from Server ....
{"status":3,"errmsg":"Expected object or value"}
I just got this url from the API console.
Ensure you are using the API key associated with your developer account registered at http://developer.surveymonkey.com, not the sample API key the console uses to let you try requests. The sample api key is not meant to be used with apps, only on the API console.
That particular error is generated when an empty string is sent for the POST data. The API expects an empty object at minimum ("{}"). If the issue pointed out by Miles above was just a typo (using 'getRequestProperty' instead of 'setRequestProperty',) check if toString on an empty JSONObject is returning "" or "{}".

Google OAuth 2.0 Authentication throwing SocketTimeoutException : Read timeout

I am trying to authenticate with Google using OAuth 2.0 for GAMv2 Apps.
GoogleCredential.Builder credentialBuilder = new GoogleCredential.Builder();
credentialBuilder.setTransport(httpTransport).setJsonFactory(jsonFactory);
credentialBuilder.setServiceAccountId(serviceAccountId);
credentialBuilder.setServiceAccountPrivateKeyFromP12File(new File(p12FileURL.toURI()));
credentialBuilder.setServiceAccountScopes(scopes);
credentialBuilder.setServiceAccountUser(userEmail);
credential = credentialBuilder.build();
credential.refreshToken();
Oauth2 userInfoService = new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credential).setApplicationName(applicationName).build();
Userinfoplus userInfo = null;
try
{
userInfo = userInfoService.userinfo().get().execute();
}
catch (IOException e)
{
logger.error("Exception_Thrown while getting User Info:", e);
}
I am using the above code for getting the userInfo and facing the following exception :
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:129)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:798)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:755)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)
at java.io.BufferedInputStream.read(BufferedInputStream.java:317)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:687)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:632)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1195)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:379)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:318)
at com.google.api.client.http.javanet.NetHttpResponse.<init>(NetHttpResponse.java:36)
at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:94)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:965)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
Until last few days, it was fine. Only in a couple of days now we are facing this issue.
Can anyone help with this issue ?
Thanks in advance.
you can get instance of HttpRequestInitializer from Oauth2.Builder and pass it as input parameter
private static HttpRequestInitializer setHttpTimeout(final HttpRequestInitializer requestInitializer) {
return new HttpRequestInitializer() {
#Override
public void initialize(HttpRequest httpRequest) throws IOException {
requestInitializer.initialize(httpRequest);
httpRequest.setConnectTimeout(3 * 60000); // 3 minutes connect timeout
httpRequest.setReadTimeout(3 * 60000); // 3 minutes read timeout
}
};
}

Resources