Skip to content
This repository has been archived by the owner on Feb 10, 2021. It is now read-only.

Implements refresh token behaviour #244

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 30 additions & 17 deletions code/app/com/feth/play/module/pa/PlayAuthenticate.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Date;

import com.feth.play.module.pa.providers.oauth2.OAuth2AuthProvider;
import play.Configuration;
import play.Logger;
import play.Play;
Expand Down Expand Up @@ -175,23 +176,35 @@ public static void storeUser(final Session session, final AuthUser authUser) {
}
}

public static boolean isLoggedIn(final Session session) {
boolean ret = session.containsKey(USER_KEY) // user is set
&& session.containsKey(PROVIDER_KEY); // provider is set
ret &= AuthProvider.Registry.hasProvider(session.get(PROVIDER_KEY)); // this
// provider
// is
// active
if (session.containsKey(EXPIRES_KEY)) {
// expiration is set
final long expires = getExpiration(session);
if (expires != AuthUser.NO_EXPIRATION) {
ret &= (new Date()).getTime() < expires; // and the session
// expires after now
}
}
return ret;
}
public static Boolean isLoggedIn(Session session) {
return isLoggedIn(getUser(session),session);
}

/**
* Check if the specified user is logged in. If session is expired, then a refresh token will be used to update the user token
*
* @param authUser
* @param session
* @return
*/
public static Boolean isLoggedIn(AuthUser authUser, Session session) {
boolean isLogged = false;
AuthProvider provider = getProvider(session.get(PROVIDER_KEY));
if (authUser != null && provider != null) {
if (authUser.expires() != AuthUser.NO_EXPIRATION) {
boolean isExpired = System.currentTimeMillis() > authUser.expires();
if (isExpired) {
if(provider instanceof OAuth2AuthProvider){
// OAuth2AuthProvider implementation can provide refresh token
isLogged = ((OAuth2AuthProvider) provider).refresh(authUser, session) != null;
}
} else {
isLogged = true;
}
}
}
return isLogged;
}

public static Result logout(final Session session) {
session.remove(USER_KEY);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,26 @@
package com.feth.play.module.pa.providers.oauth2;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.feth.play.module.pa.PlayAuthenticate;
import com.feth.play.module.pa.exceptions.*;
import com.feth.play.module.pa.providers.ext.ExternalAuthProvider;
import com.feth.play.module.pa.user.AuthUser;
import com.feth.play.module.pa.user.AuthUserIdentity;
import com.google.common.base.Strings;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;

import play.Application;
import play.Configuration;
import play.Logger;
import play.i18n.Messages;
import play.libs.ws.WS;
import play.libs.ws.WSResponse;
import play.libs.ws.WSRequestHolder;
import play.mvc.Http;
import play.libs.ws.WSResponse;
import play.mvc.Http.Context;
import play.mvc.Http.Request;
import play.mvc.Http.Session;

import com.feth.play.module.pa.PlayAuthenticate;
import com.feth.play.module.pa.providers.ext.ExternalAuthProvider;
import com.feth.play.module.pa.user.AuthUser;
import com.feth.play.module.pa.user.AuthUserIdentity;
import java.util.*;

public abstract class OAuth2AuthProvider<U extends AuthUserIdentity, I extends OAuth2AuthInfo>
extends ExternalAuthProvider {
Expand All @@ -52,6 +46,7 @@ protected List<String> neededSettingKeys() {
public static abstract class SettingKeys {
public static final String AUTHORIZATION_URL = "authorizationUrl";
public static final String ACCESS_TOKEN_URL = "accessTokenUrl";
public static final String REFRESH_TOKEN_URL = "refreshTokenUrl";
public static final String CLIENT_ID = "clientId";
public static final String CLIENT_SECRET = "clientSecret";
public static final String SCOPE = "scope";
Expand Down Expand Up @@ -201,6 +196,14 @@ public Object authenticate(final Context context, final Object payload)
}
final String code = request.getQueryString(Constants.CODE);
final I info = getAccessToken(code, request);
// Store refresh token to cache
String token = info.getRefreshToken();
if(!Strings.isNullOrEmpty(token)) {
if (Logger.isDebugEnabled()) {
Logger.debug("add to cache refreshToken=" + token);
}
PlayAuthenticate.storeInCache(context.session(), OAuth2AuthProvider.Constants.REFRESH_TOKEN, token);
}
return transform(info, callbackState);
} else {
// no auth, yet
Expand Down Expand Up @@ -240,4 +243,16 @@ public void afterSave(final AuthUser user, final Object identity, final Session
*/
protected abstract AuthUserIdentity transform(final I info,
final String state) throws AuthException;

/**
* Method used to refresh a token when the token was expired.
*
* @param authUser
* @param session
* @return a refreshed authuser or null otherwise
*/
public AuthUser refresh(AuthUser authUser, Session session) {
return null;
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
package com.feth.play.module.pa.providers.oauth2.google;

import com.feth.play.module.pa.PlayAuthenticate;
import com.feth.play.module.pa.user.AuthUser;
import com.feth.play.module.pa.user.SessionAuthUser;
import com.google.common.base.Strings;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.ContentType;
import org.apache.http.message.BasicNameValuePair;
import play.Application;
import play.Configuration;
import play.Logger;
import play.libs.ws.WS;
import play.libs.ws.WSRequestHolder;
import play.libs.ws.WSResponse;

import com.fasterxml.jackson.databind.JsonNode;
import com.feth.play.module.pa.exceptions.AccessTokenException;
import com.feth.play.module.pa.exceptions.AuthException;
import com.feth.play.module.pa.providers.oauth2.OAuth2AuthProvider;
import play.mvc.Http;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class GoogleAuthProvider extends
OAuth2AuthProvider<GoogleAuthUser, GoogleAuthInfo> {
Expand Down Expand Up @@ -62,4 +78,43 @@ protected GoogleAuthInfo buildInfo(final WSResponse r)
}
}

@Override
public AuthUser refresh(AuthUser authUser, Http.Session session) {
Configuration config = PlayAuthenticate.getConfiguration().getConfig(PROVIDER_KEY);
String url = config.getString(SettingKeys.REFRESH_TOKEN_URL);
String refreshToken = PlayAuthenticate.getFromCache(session, OAuth2AuthProvider.Constants.REFRESH_TOKEN);
if (Strings.isNullOrEmpty(refreshToken)){
Logger.error("refresh token not found from cache");
return null;
}
if(Strings.isNullOrEmpty(url)) {
return null;
}
final List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair(OAuth2AuthProvider.Constants.REFRESH_TOKEN, refreshToken));
params.add(new BasicNameValuePair(OAuth2AuthProvider.Constants.CLIENT_ID, config.getString(OAuth2AuthProvider.SettingKeys.CLIENT_ID)));
params.add(new BasicNameValuePair(OAuth2AuthProvider.Constants.CLIENT_SECRET, config.getString(OAuth2AuthProvider.SettingKeys.CLIENT_SECRET)));
params.add(new BasicNameValuePair(OAuth2AuthProvider.Constants.GRANT_TYPE, "refresh_token"));

final WSRequestHolder request = WS
.url(url);
request.setContentType(ContentType.APPLICATION_FORM_URLENCODED.toString());
WSResponse response = request.post(URLEncodedUtils.format(params, Charset.forName("UTF-8"))).get(getTimeout());
AuthUser refreshedUser = null;
if (response == null ) {
Logger.error("[" + authUser.getId() + "] refresh token | fail | No response received for " + url);
} else if(response.getStatus() != 200) {
Logger.error("[" + authUser.getId() + "] refresh token | fail | HTTP_STATUS="+response.getStatus()+response.getBody());
} else {
JsonNode payload = response.asJson();
JsonNode expiresNode = payload.get(OAuth2AuthProvider.Constants.EXPIRES_IN);
if(expiresNode != null) {
long expiresDate = new Date().getTime() + expiresNode.asLong() * 1000;
refreshedUser = new SessionAuthUser(authUser.getProvider(), authUser.getId(), expiresDate);
//update value in session
PlayAuthenticate.storeUser(session, refreshedUser);
}
}
return refreshedUser;
}
}
3 changes: 2 additions & 1 deletion code/conf/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,12 @@ play-authenticate {
}
authorizationUrl="https://accounts.google.com/o/oauth2/auth"
accessTokenUrl="https://accounts.google.com/o/oauth2/token"
refreshTokenUrl="https://www.googleapis.com/oauth2/v3/token"
userInfoUrl="https://www.googleapis.com/oauth2/v1/userinfo"
scope="https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email"

# Additional parameters - Read more about them here: https://developers.google.com/accounts/docs/OAuth2WebServer#offline
# accessType="offline"
accessType="offline"
# approvalPrompt="force"

# Get the credentials here: https://code.google.com/apis/console
Expand Down
2 changes: 1 addition & 1 deletion code/version.sbt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version in ThisBuild := "0.6.9-SNAPSHOT"
version in ThisBuild := "0.6.10-SNAPSHOT"