mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
23.05.2016 f0f8d36cfc0b971249be38021112bfa0754c44c1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap.authz;
 
import static org.forgerock.util.Reject.checkNotNull;
 
import org.forgerock.http.protocol.Headers;
import org.forgerock.util.Function;
import org.forgerock.util.Pair;
import org.forgerock.util.encode.Base64;
import org.forgerock.util.promise.NeverThrowsException;
 
/**
 * Factory method for function extracting credentials from HTTP request {@link Headers}.
 */
public final class CredentialExtractors {
 
    /** HTTP Header sent by the client with HTTP basic authentication. */
    public static final String HTTP_BASIC_AUTH_HEADER = "Authorization";
 
    private CredentialExtractors() {
    }
 
    /**
     * Creates a function which extracts the user's credentials from the standard HTTP Basic header.
     *
     * @return the basic extractor singleton
     */
    public static Function<Headers, Pair<String, String>, NeverThrowsException> httpBasicExtractor() {
        return HttpBasicExtractor.INSTANCE;
    }
 
    /**
     * Creates a function which extracts the user's credentials from custom HTTP header in addition of the standard HTTP
     * Basic one.
     *
     * @param customHeaderUsername
     *            Name of the additional header to check for the user's name
     * @param customHeaderPassword
     *            Name of the additional header to check for the user's password
     * @return A new credentials extractors looking for custom header.
     */
    public static Function<Headers, Pair<String, String>, NeverThrowsException> newCustomHeaderExtractor(
            String customHeaderUsername, String customHeaderPassword) {
        return new CustomHeaderExtractor(customHeaderUsername, customHeaderPassword);
    }
 
    /** Extract the user's credentials from custom {@link Headers}. */
    private static final class CustomHeaderExtractor
            implements Function<Headers, Pair<String, String>, NeverThrowsException> {
 
        private final String customHeaderUsername;
        private final String customHeaderPassword;
 
        /**
         * Create a new CustomHeaderExtractor.
         *
         * @param customHeaderUsername
         *            Name of the header containing the username
         * @param customHeaderPassword
         *            Name of the header containing the password
         * @throws NullPointerException
         *             if a parameter is null.
         */
        public CustomHeaderExtractor(String customHeaderUsername, String customHeaderPassword) {
            this.customHeaderUsername = checkNotNull(customHeaderUsername, "customHeaderUsername cannot be null");
            this.customHeaderPassword = checkNotNull(customHeaderPassword, "customHeaderPassword cannot be null");
        }
 
        @Override
        public Pair<String, String> apply(Headers headers) {
            final String userName = headers.getFirst(customHeaderUsername);
            final String password = headers.getFirst(customHeaderPassword);
            if (userName != null && password != null) {
                return Pair.of(userName, password);
            }
            return HttpBasicExtractor.INSTANCE.apply(headers);
        }
    }
 
    /** Extract the user's credentials from the standard HTTP Basic {@link Headers}. */
    private static final class HttpBasicExtractor
            implements Function<Headers, Pair<String, String>, NeverThrowsException> {
 
        /** Reference to the HttpBasicExtractor Singleton. */
        public static final HttpBasicExtractor INSTANCE = new HttpBasicExtractor();
 
        private HttpBasicExtractor() { }
 
        @Override
        public Pair<String, String> apply(Headers headers) {
            final String httpBasicAuthHeader = headers.getFirst(HTTP_BASIC_AUTH_HEADER);
            if (httpBasicAuthHeader != null) {
                final Pair<String, String> userCredentials = parseUsernamePassword(httpBasicAuthHeader);
                if (userCredentials != null) {
                    return userCredentials;
                }
            }
            return null;
        }
 
        private Pair<String, String> parseUsernamePassword(String authHeader) {
            if (authHeader != null && (authHeader.toLowerCase().startsWith("basic"))) {
                // We received authentication info
                // Example received header:
                // "Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
                final String base64UserCredentials = authHeader.substring("basic".length() + 1);
                // Example usage of base64:
                // Base64("Aladdin:open sesame") = "QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
                final String userCredentials = new String(Base64.decode(base64UserCredentials));
                String[] split = userCredentials.split(":");
                if (split.length == 2) {
                    return Pair.of(split[0], split[1]);
                }
            }
            return null;
        }
    }
}