Created
February 6, 2013 16:01
-
-
Save smola/4723534 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class MyUsernamePasswordAuthProvider | |
extends /* ........ */ { | |
/* ... MORE ... */ | |
/** | |
* XXX: Ugly hack for Remember Me feature. | |
*/ | |
public static Result handleLogin(final Context ctx, final boolean rememberMe) { | |
final Result result = UsernamePasswordAuthProvider.handleLogin(ctx); | |
if (rememberMe) { | |
//XXX: Is this secure? (SECURITY) | |
// We are logged in, remember. | |
RememberMe.remember(ctx); | |
} | |
return result; | |
} | |
/* ... MORE ... */ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package providers; | |
import java.util.List; | |
import java.util.UUID; | |
import models.TokenAction; | |
import models.User; | |
import org.joda.time.DateTime; | |
import org.joda.time.Duration; | |
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import play.mvc.Http.Context; | |
import play.mvc.Http.Cookie; | |
import play.mvc.Http.Cookies; | |
import com.feth.play.module.pa.PlayAuthenticate; | |
import com.google.common.base.Splitter; | |
import com.google.common.collect.ImmutableList; | |
public class RememberMe { | |
private static final Logger log = LoggerFactory.getLogger(RememberMe.class); | |
private static int getTimeout() { | |
return 30; | |
} | |
private static String getCookieName() { | |
return "REMEMBERME"; | |
} | |
public static TokenAction getTokenAction(final Context ctx) { | |
final Cookies cookies = ctx.request().cookies(); | |
final Cookie cookie = cookies.get(getCookieName()); | |
if (cookie == null) { | |
return null; | |
} | |
final List<String> fields = ImmutableList.copyOf(Splitter.on('|').split(cookie.value())); | |
if (fields.size() != 2) { | |
log.warn("Discarding marlformed cookie: " + cookie.value()); | |
ctx.response().discardCookies(getCookieName()); | |
return null; | |
} | |
Long userId = null; | |
try { | |
userId = Long.valueOf(fields.get(0)); | |
} catch (NumberFormatException ex) { | |
log.warn("Discarding marlformed cookie: " + cookie.value()); | |
ctx.response().discardCookies(getCookieName()); | |
return null; | |
} | |
final User user = User.find.byId(userId); | |
if (user == null || !user.active) { | |
log.warn("Discarding cookie for invalid user: " + cookie.value()); | |
ctx.response().discardCookies(getCookieName()); | |
return null; | |
} | |
final String randKey = fields.get(1); | |
final TokenAction tokenAction = TokenAction.find | |
.fetch("targetUser").where() | |
.eq("target_user_id", userId) | |
.eq("type", TokenAction.Type.REMEMBER_ME) | |
.eq("token", randKey) | |
.findUnique(); | |
if (tokenAction == null) { | |
log.debug("Discarding cookie inexistent tokenAction: " + cookie.value()); | |
ctx.response().discardCookies(getCookieName()); | |
return null; | |
} | |
if (tokenAction.targetUser == null) { | |
log.debug("Discarding cookie inexistent tokenAction.targetUser: " + cookie.value()); | |
tokenAction.delete(); | |
ctx.response().discardCookies(getCookieName()); | |
return null; | |
} | |
if (new DateTime().isAfter(new DateTime(tokenAction.expires))) { | |
tokenAction.delete(); | |
return null; | |
} | |
return tokenAction; | |
} | |
public static boolean authenticate(final Context ctx) { | |
final TokenAction tokenAction = getTokenAction(ctx); | |
if (tokenAction == null) { | |
return false; | |
} | |
PlayAuthenticate.storeUser(ctx.session(), new MyLoginUsernamePasswordAuthUser(tokenAction.targetUser.email)); | |
return true; | |
} | |
public static void remember(final Context ctx) { | |
remember(ctx, User.getLocalUser(ctx.session())); | |
} | |
public static void remember(final Context ctx, final User user) { | |
if (user == null) { | |
return; | |
} | |
final String token = UUID.randomUUID().toString(); | |
final TokenAction tokenAction = TokenAction.create( | |
TokenAction.Type.REMEMBER_ME, | |
token, | |
user); | |
tokenAction.expires = new DateTime().plus(Duration.standardDays(getTimeout())).toDate(); | |
tokenAction.save(); | |
ctx.response().setCookie( | |
getCookieName(), | |
user.id + "|" + token, | |
getTimeout()*24*60*60, // MaxAge in seconds | |
"/", // Path | |
null, | |
false, | |
true); | |
for (final Cookie cookie : ctx.response().cookies()) { | |
log.error("FOO - " + cookie.toString()); | |
} | |
} | |
public static void forget(final Context ctx) { | |
final TokenAction tokenAction = getTokenAction(ctx); | |
if (tokenAction != null) { | |
ctx.response().discardCookies(getCookieName()); | |
tokenAction.delete(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package controllers; | |
import com.feth.play.module.pa.PlayAuthenticate; | |
import play.mvc.Action.Simple; | |
import play.mvc.Http.Context; | |
import play.mvc.Result; | |
import providers.RememberMe; | |
public class RememberMeAction extends Simple { | |
@Override | |
public Result call(Context ctx) throws Throwable { | |
if (!PlayAuthenticate.isLoggedIn(ctx.session())) { | |
RememberMe.authenticate(ctx); | |
} | |
return delegate.call(ctx); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This implementation is currently semi-broken since there is a conflict between the Set-Cookie for PLAY_SESSION and REMEMBER_ME. As it is, it does not work with recent Netty versions (AFAIK).