From df812aa75aac92ff4685dcf052b9ac4ed8d12fe6 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 25 Dec 2019 16:17:43 +0300 Subject: Cleanup SocialLogin --- .../com/github/scribejava/apis/AppleSignInApi.java | 62 ++++++++++++++++++++++ .../java/com/juick/server/api/ApiSocialLogin.java | 38 ++----------- .../juick/server/www/controllers/SocialLogin.java | 40 ++------------ 3 files changed, 72 insertions(+), 68 deletions(-) (limited to 'src/main/java/com') diff --git a/src/main/java/com/github/scribejava/apis/AppleSignInApi.java b/src/main/java/com/github/scribejava/apis/AppleSignInApi.java index be14ef16..14b7f0e6 100644 --- a/src/main/java/com/github/scribejava/apis/AppleSignInApi.java +++ b/src/main/java/com/github/scribejava/apis/AppleSignInApi.java @@ -18,7 +18,25 @@ package com.github.scribejava.apis; import com.github.scribejava.core.builder.api.DefaultApi20; +import com.github.scribejava.core.model.OAuth2AccessToken; import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.jwk.source.JWKSource; +import com.nimbusds.jose.jwk.source.RemoteJWKSet; +import com.nimbusds.jose.proc.BadJOSEException; +import com.nimbusds.jose.proc.JWSKeySelector; +import com.nimbusds.jose.proc.JWSVerificationKeySelector; +import com.nimbusds.jose.proc.SecurityContext; +import com.nimbusds.jwt.proc.ConfigurableJWTProcessor; +import com.nimbusds.jwt.proc.DefaultJWTClaimsVerifier; +import com.nimbusds.jwt.proc.DefaultJWTProcessor; +import net.minidev.json.JSONObject; + +import java.net.MalformedURLException; +import java.net.URL; +import java.text.ParseException; +import java.util.Optional; public class AppleSignInApi extends DefaultApi20 { @@ -42,4 +60,48 @@ public class AppleSignInApi extends DefaultApi20 { public ClientAuthentication getClientAuthentication() { return new AppleClientAuthentication(clientSecretGenerator); } + + public Optional validateToken(String idToken) { + +// Create a JWT processor for the access tokens + ConfigurableJWTProcessor jwtProcessor = + new DefaultJWTProcessor<>(); + +// The public RSA keys to validate the signatures will be sourced from the +// OAuth 2.0 server's JWK set, published at a well-known URL. The RemoteJWKSet +// object caches the retrieved keys to speed up subsequent look-ups and can +// also handle key-rollover + JWKSource keySource = + null; + try { + keySource = new RemoteJWKSet<>(new URL("https://appleid.apple.com/auth/keys")); + } catch (MalformedURLException e) { + return Optional.empty(); + } + +// The expected JWS algorithm of the access tokens (agreed out-of-band) + JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256; + +// Configure the JWT processor with a key selector to feed matching public +// RSA keys sourced from the JWK set URL + JWSKeySelector keySelector = + new JWSVerificationKeySelector<>(expectedJWSAlg, keySource); + + jwtProcessor.setJWSKeySelector(keySelector); + +// Set the required JWT claims for access tokens issued by the server + jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>()); + +// Process the token + JSONObject claimsSet = null; + try { + claimsSet = jwtProcessor.process(idToken, null).toJSONObject(); + } catch (ParseException | BadJOSEException | JOSEException e) { + return Optional.empty(); + } + + var email = claimsSet.getAsString("email"); + var verified = claimsSet.getAsString("email_verified").equals("true"); + return verified ? Optional.of(email) : Optional.empty(); + } } diff --git a/src/main/java/com/juick/server/api/ApiSocialLogin.java b/src/main/java/com/juick/server/api/ApiSocialLogin.java index 164c71a4..8ca7d6d8 100644 --- a/src/main/java/com/juick/server/api/ApiSocialLogin.java +++ b/src/main/java/com/juick/server/api/ApiSocialLogin.java @@ -302,39 +302,11 @@ public class ApiSocialLogin { var jsonNode = jsonMapper.readTree(token.getRawResponse()); var idToken = jsonNode.get("id_token").textValue(); -// Create a JWT processor for the access tokens - ConfigurableJWTProcessor jwtProcessor = - new DefaultJWTProcessor<>(); + AppleSignInApi api = (AppleSignInApi) appleSignInService.getApi(); + var email = api.validateToken(idToken); -// The public RSA keys to validate the signatures will be sourced from the -// OAuth 2.0 server's JWK set, published at a well-known URL. The RemoteJWKSet -// object caches the retrieved keys to speed up subsequent look-ups and can -// also handle key-rollover - JWKSource keySource = - new RemoteJWKSet<>(new URL("https://appleid.apple.com/auth/keys")); - -// The expected JWS algorithm of the access tokens (agreed out-of-band) - JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256; - -// Configure the JWT processor with a key selector to feed matching public -// RSA keys sourced from the JWK set URL - JWSKeySelector keySelector = - new JWSVerificationKeySelector<>(expectedJWSAlg, keySource); - - jwtProcessor.setJWSKeySelector(keySelector); - -// Set the required JWT claims for access tokens issued by the Connect2id -// server, may differ with other servers - jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>()); - -// Process the token - JSONObject claimsSet = jwtProcessor.process(idToken, null).toJSONObject(); - - var email = claimsSet.getAsString("email"); - var verified = claimsSet.getAsString("email_verified").equals("true"); - - if (verified) { - com.juick.User user = userService.getUserByEmail(email); + if (email.isPresent()) { + com.juick.User user = userService.getUserByEmail(email.get()); if (!user.isAnonymous()) { String redirectUrl = crosspostService.verifyVKState(body.get("state")); if (StringUtils.isBlank(redirectUrl)) { @@ -347,7 +319,7 @@ public class ApiSocialLogin { return "redirect:" + uriComponentsBuilder.build().toUriString(); } else { String verificationCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase(); - emailService.addVerificationCode(null, email, verificationCode); + emailService.addVerificationCode(null, email.get(), verificationCode); return "redirect:/signup?type=email&hash=" + verificationCode; } } diff --git a/src/main/java/com/juick/server/www/controllers/SocialLogin.java b/src/main/java/com/juick/server/www/controllers/SocialLogin.java index eb1e3cfe..2985e42f 100644 --- a/src/main/java/com/juick/server/www/controllers/SocialLogin.java +++ b/src/main/java/com/juick/server/www/controllers/SocialLogin.java @@ -360,40 +360,10 @@ public class SocialLogin { OAuth2AccessToken token = appleSignInService.getAccessToken(body.get("code")); var jsonNode = jsonMapper.readTree(token.getRawResponse()); var idToken = jsonNode.get("id_token").textValue(); - -// Create a JWT processor for the access tokens - ConfigurableJWTProcessor jwtProcessor = - new DefaultJWTProcessor<>(); - -// The public RSA keys to validate the signatures will be sourced from the -// OAuth 2.0 server's JWK set, published at a well-known URL. The RemoteJWKSet -// object caches the retrieved keys to speed up subsequent look-ups and can -// also handle key-rollover - JWKSource keySource = - new RemoteJWKSet<>(new URL("https://appleid.apple.com/auth/keys")); - -// The expected JWS algorithm of the access tokens (agreed out-of-band) - JWSAlgorithm expectedJWSAlg = JWSAlgorithm.RS256; - -// Configure the JWT processor with a key selector to feed matching public -// RSA keys sourced from the JWK set URL - JWSKeySelector keySelector = - new JWSVerificationKeySelector<>(expectedJWSAlg, keySource); - - jwtProcessor.setJWSKeySelector(keySelector); - -// Set the required JWT claims for access tokens issued by the Connect2id -// server, may differ with other servers - jwtProcessor.setJWTClaimsSetVerifier(new DefaultJWTClaimsVerifier<>()); - -// Process the token - JSONObject claimsSet = jwtProcessor.process(idToken, null).toJSONObject(); - - var email = claimsSet.getAsString("email"); - var verified = claimsSet.getAsString("email_verified").equals("true"); - - if (verified) { - com.juick.User user = userService.getUserByEmail(email); + AppleSignInApi api = (AppleSignInApi) appleSignInService.getApi(); + var email = api.validateToken(idToken); + if (email.isPresent()) { + com.juick.User user = userService.getUserByEmail(email.get()); if (!user.isAnonymous()) { Cookie c = new Cookie("hash", userService.getHashByUID(user.getUid())); c.setMaxAge(50 * 24 * 60 * 60); @@ -401,7 +371,7 @@ public class SocialLogin { return "redirect:/"; } else { String verificationCode = RandomStringUtils.randomAlphanumeric(8).toUpperCase(); - emailService.addVerificationCode(null, email, verificationCode); + emailService.addVerificationCode(null, email.get(), verificationCode); return "redirect:/signup?type=email&hash=" + verificationCode; } } -- cgit v1.2.3