I am looking some way to make some authentication for my play framework app: I want allow/disallow the whole access to non authenticated users
Is there exists some working module/solution for it? I don't need any forms for auth, just 401 HTTP response for non authenticated users (like Apache .htacccess "AuthType Basic" mode).
I've updated Jonck van der Kogel's answer to be more strict in parsing the authorization header, to not fail with ugly exceptions if the auth header is invalid, to allow passwords with ':', and to work with Play 2.6:
So, BasicAuthAction class:
import java.io.UnsupportedEncodingException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import org.apache.commons.codec.binary.Base64;
import play.Logger;
import play.Logger.ALogger;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Http.Context;
import play.mvc.Result;
public class BasicAuthAction extends Action<Result> {
private static ALogger log = Logger.of(BasicAuthAction.class);
private static final String AUTHORIZATION = "Authorization";
private static final String WWW_AUTHENTICATE = "WWW-Authenticate";
private static final String REALM = "Basic realm=\"Realm\"";
@Override
public CompletionStage<Result> call(Context context) {
String authHeader = context.request().getHeader(AUTHORIZATION);
if (authHeader == null) {
context.response().setHeader(WWW_AUTHENTICATE, REALM);
return CompletableFuture.completedFuture(status(Http.Status.UNAUTHORIZED, "Needs authorization"));
}
String[] credentials;
try {
credentials = parseAuthHeader(authHeader);
} catch (Exception e) {
log.warn("Cannot parse basic auth info", e);
return CompletableFuture.completedFuture(status(Http.Status.FORBIDDEN, "Invalid auth header"));
}
String username = credentials[0];
String password = credentials[1];
boolean loginCorrect = checkLogin(username, password);
if (!loginCorrect) {
log.warn("Incorrect basic auth login, username=" + username);
return CompletableFuture.completedFuture(status(Http.Status.FORBIDDEN, "Forbidden"));
} else {
context.request().setUsername(username);
log.info("Successful basic auth login, username=" + username);
return delegate.call(context);
}
}
private String[] parseAuthHeader(String authHeader) throws UnsupportedEncodingException {
if (!authHeader.startsWith("Basic ")) {
throw new IllegalArgumentException("Invalid Authorization header");
}
String[] credString;
String auth = authHeader.substring(6);
byte[] decodedAuth = new Base64().decode(auth);
credString = new String(decodedAuth, "UTF-8").split(":", 2);
if (credString.length != 2) {
throw new IllegalArgumentException("Invalid Authorization header");
}
return credString;
}
private boolean checkLogin(String username, String password) {
/// change this
return username.equals("vlad");
}
}
And then, in controller classes:
@With(BasicAuthAction.class)
public Result authPage() {
String username = request().username();
return Result.ok("Successful login as user: " + username + "! Here's your data: ...");
}
You can try this filter:
https://github.com/Kaliber/play-basic-authentication-filter
It looks pretty simple to use and configure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With