/**
 * 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) {
            if (LdapService.useLdap) {
                return  UserApp.authenticateWithLdap(authUser.loginId, authUser.password);
            } else {
                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);
    }
}

@@ -1357,16 +1357,112 @@
  + %22%5C%22%22;
+%0A%0A        play.Logger.error(%22-----------%22 + Http.HeaderNames.WWW_AUTHENTICATE +%22:%22 + challenge);
 %0A       
@@ -3096,32 +3096,159 @@
 uthUser;%0A    %7D%0A%0A
+    // !! Important !! For ldap, intentionally, user email is used for ldap authentication%0A    // instead of authUser.loginId.%0A
     public User 
@@ -3479,16 +3479,24 @@
 ntial);%0A
+        
 %0A       
@@ -3536,34 +3536,344 @@
     
-if (LdapService.useLdap) %7B
+String credentialKey = authUser.loginId;%0A            if (LdapService.useLdap) %7B%0A                // Notice: Email is used for LDAP authentication%0A                User targetUser = User.findByLoginId(authUser.loginId);%0A                if(!targetUser.isAnonymous()) %7B%0A                    credentialKey = targetUser.email;%0A                %7D
 %0A   
@@ -3922,32 +3922,29 @@
 ithLdap(
-authUser.loginId
+credentialKey
 , authUs

Improve auth compatibility for git commandline usage