5151
5252public class KeycloakOAuth2Provider extends AdapterBase implements UserOAuth2Authenticator {
5353
54+ protected String idToken = null ;
55+
5456 @ Inject
5557 OauthProviderDao oauthProviderDao ;
5658
@@ -89,6 +91,7 @@ public boolean verifyUser(String email, String secretCode) {
8991 if (StringUtils .isBlank (verifiedEmail ) || !email .equals (verifiedEmail )) {
9092 throw new CloudRuntimeException ("Unable to verify the email address with the provided secret" );
9193 }
94+ clearIdToken ();
9295
9396 return true ;
9497 }
@@ -97,45 +100,59 @@ public boolean verifyUser(String email, String secretCode) {
97100 public String verifyCodeAndFetchEmail (String secretCode ) {
98101 OauthProviderVO provider = oauthProviderDao .findByProvider (getName ());
99102
100- String auth = provider .getClientId () + ":" + provider .getSecretKey ();
101- String encodedAuth = Base64 .getEncoder ().encodeToString (auth .getBytes (StandardCharsets .UTF_8 ));
103+ if (StringUtils .isBlank (idToken )) {
104+ String auth = provider .getClientId () + ":" + provider .getSecretKey ();
105+ String encodedAuth = Base64 .getEncoder ().encodeToString (auth .getBytes (StandardCharsets .UTF_8 ));
102106
103- List <NameValuePair > params = new ArrayList <>();
104- params .add (new BasicNameValuePair ("grant_type" , "authorization_code" ));
105- params .add (new BasicNameValuePair ("code" , secretCode ));
106- params .add (new BasicNameValuePair ("redirect_uri" , provider .getRedirectUri ()));
107+ List <NameValuePair > params = new ArrayList <>();
108+ params .add (new BasicNameValuePair ("grant_type" , "authorization_code" ));
109+ params .add (new BasicNameValuePair ("code" , secretCode ));
110+ params .add (new BasicNameValuePair ("redirect_uri" , provider .getRedirectUri ()));
107111
108- HttpPost post = new HttpPost (provider .getTokenUrl ());
109- post .setHeader (HttpHeaders .AUTHORIZATION , "Basic " + encodedAuth );
112+ HttpPost post = new HttpPost (provider .getTokenUrl ());
113+ post .setHeader (HttpHeaders .AUTHORIZATION , "Basic " + encodedAuth );
110114
111- try {
112- post .setEntity (new UrlEncodedFormEntity (params ));
113- } catch (UnsupportedEncodingException e ) {
114- throw new CloudRuntimeException ("Unable to generating URL parameters: " + e .getMessage ());
115- }
115+ try {
116+ post .setEntity (new UrlEncodedFormEntity (params ));
117+ } catch (UnsupportedEncodingException e ) {
118+ throw new CloudRuntimeException ("Unable to generating URL parameters: " + e .getMessage ());
119+ }
116120
117- try (CloseableHttpResponse response = httpClient .execute (post )) {
118- String body = EntityUtils .toString (response .getEntity ());
121+ try (CloseableHttpResponse response = httpClient .execute (post )) {
122+ String body = EntityUtils .toString (response .getEntity ());
119123
120- if (response .getStatusLine ().getStatusCode () != 200 ) {
121- throw new CloudRuntimeException ("Keycloak error during token generation: " + body );
122- }
124+ if (response .getStatusLine ().getStatusCode () != 200 ) {
125+ throw new CloudRuntimeException ("Keycloak error during token generation: " + body );
126+ }
123127
124- JsonObject json = JsonParser .parseString (body ).getAsJsonObject ();
125- String idToken = json .get ("id_token" ).getAsString ();
128+ JsonObject json = JsonParser .parseString (body ).getAsJsonObject ();
129+ String idToken = json .get ("id_token" ).getAsString ();
130+ validateIdToken (idToken , provider );
126131
127- return validateIdTokenAndGetEmail (idToken , provider );
128- } catch (IOException e ) {
129- throw new CloudRuntimeException ("Unable to connect to Keycloak server" , e );
132+ this .idToken = idToken ;
133+ } catch (IOException e ) {
134+ throw new CloudRuntimeException ("Unable to connect to Keycloak server" , e );
135+ }
130136 }
137+
138+ return obtainEmail (idToken , provider );
131139 }
132140
133141 @ Override
134142 public String getUserEmailAddress () throws CloudRuntimeException {
135143 return null ;
136144 }
137145
138- private String validateIdTokenAndGetEmail (String idTokenStr , OauthProviderVO provider ) {
146+ private void validateIdToken (String idTokenStr , OauthProviderVO provider ) {
147+ JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer (idTokenStr );
148+ JwtClaims claims = jwtConsumer .getJwtToken ().getClaims ();
149+
150+ if (!claims .getAudiences ().contains (provider .getClientId ())) {
151+ throw new CloudAuthenticationException ("Audience mismatch" );
152+ }
153+ }
154+
155+ private String obtainEmail (String idTokenStr , OauthProviderVO provider ) {
139156 JwsJwtCompactConsumer jwtConsumer = new JwsJwtCompactConsumer (idTokenStr );
140157 JwtClaims claims = jwtConsumer .getJwtToken ().getClaims ();
141158
@@ -146,6 +163,10 @@ private String validateIdTokenAndGetEmail(String idTokenStr, OauthProviderVO pro
146163 return (String ) claims .getClaim ("email" );
147164 }
148165
166+ protected void clearIdToken () {
167+ idToken = null ;
168+ }
169+
149170 public void setHttpClient (CloseableHttpClient httpClient ) {
150171 this .httpClient = httpClient ;
151172 }
0 commit comments