/* * 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, 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, 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, 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 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, NeverThrowsException> { /** Reference to the HttpBasicExtractor Singleton. */ public static final HttpBasicExtractor INSTANCE = new HttpBasicExtractor(); private HttpBasicExtractor() { } @Override public Pair apply(Headers headers) { final String httpBasicAuthHeader = headers.getFirst(HTTP_BASIC_AUTH_HEADER); if (httpBasicAuthHeader != null) { final Pair userCredentials = parseUsernamePassword(httpBasicAuthHeader); if (userCredentials != null) { return userCredentials; } } return null; } private Pair 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; } } }