/**
* Yobi, Project Hosting SW
*
* Copyright 2012 NAVER Corp.
* http://yobi.io
*
* @author Yi EungJun
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utils;
import controllers.UserApp;
import models.User;
import org.apache.commons.codec.binary.Base64;
import play.libs.F.Promise;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Http.Context;
import play.mvc.Http.Request;
import play.mvc.Http.Response;
import play.mvc.Result;
import java.io.UnsupportedEncodingException;
public class BasicAuthAction extends Action<Object> {
private static final String REALM = "Yobi";
public static Result unauthorized(Response response) {
// challenge = "Basic" realm
// realm = "realm" "=" realm-value
// realm-value = quoted-string
String challenge = "Basic realm=\"" + REALM + "\"";
response.setHeader(Http.HeaderNames.WWW_AUTHENTICATE, challenge);
return unauthorized("Invalid username or password");
}
public static User parseCredentials(String credentials) throws MalformedCredentialsException, UnsupportedEncodingException {
// credentials = "Basic" basic-credentials
// basic-credentials = base64-user-pass
// base64-user-pass = <base64 [4] encoding of user-pass,
// user-pass = userid ":" password
// userid = *<TEXT excluding ":">
// password = *TEXT
if (credentials == null) {
return null;
}
byte[] userpassBytes = Base64.decodeBase64(credentials.substring(6));
// Use ISO-8859-1 only and not others, even if in RFC 2616, Section 2.2 "Basic Rules" allows
// TEXT to be encoded according to the rules of RFC 2047.
//
// Why: Julian Reschke, an editor for Authentication Scheme Registration of HTTPbis, said
// "RFC 2047 encoding doesn't apply in this case." and "the HTTPbis specs will not mention
// RFC 2047 anymore." See
// http://stackoverflow.com/questions/7242316/what-encoding-should-i-use-for-http-basic-authentication#comment11372987_9056877
String userpass = new String(userpassBytes, "ISO-8859-1");
int colonAt = userpass.indexOf(':');
if (colonAt < 0) {
throw new MalformedCredentialsException();
}
User authUser = new User();
authUser.loginId = userpass.substring(0, colonAt);
authUser.password = userpass.substring(colonAt + 1);
return authUser;
}
public User authenticate(Request request) throws UnsupportedEncodingException, MalformedCredentialsException {
String credential = request.getHeader(Http.HeaderNames.AUTHORIZATION);
User authUser = parseCredentials(credential);
if (authUser != null) {
return UserApp.authenticateWithPlainPassword(authUser.loginId, authUser.password);
} else {
return User.anonymous;
}
}
@Override
public Promise<Result> call(Context context) throws Throwable {
User user;
try {
user = authenticate(context.request());
} catch (MalformedCredentialsException error) {
Promise<Result> promise = Promise.pure((Result) badRequest());
AccessLogger.log(context.request(), promise, null);
return promise;
} catch (UnsupportedEncodingException e) {
Promise<Result> promise = Promise.pure((Result) internalServerError());
AccessLogger.log(context.request(), promise, null);
return promise;
}
if (!user.isAnonymous()) {
UserApp.addUserInfoToSession(user);
}
return delegate.call(context);
}
}