io.helidon.security.provider.httpauth.HttpBasicAuthProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of helidon-security-provider-http-auth Show documentation
Show all versions of helidon-security-provider-http-auth Show documentation
HTTP basic and digest authentication provider
/*
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
*
* 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 io.helidon.security.provider.httpauth;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.helidon.common.CollectionsHelper;
import io.helidon.common.OptionalHelper;
import io.helidon.config.Config;
import io.helidon.security.AuthenticationResponse;
import io.helidon.security.EndpointConfig;
import io.helidon.security.OutboundSecurityResponse;
import io.helidon.security.Principal;
import io.helidon.security.ProviderRequest;
import io.helidon.security.Role;
import io.helidon.security.SecurityContext;
import io.helidon.security.SecurityEnvironment;
import io.helidon.security.Subject;
import io.helidon.security.SubjectType;
import io.helidon.security.spi.AuthenticationProvider;
import io.helidon.security.spi.OutboundSecurityProvider;
import io.helidon.security.spi.SynchronousProvider;
/**
* Http authentication security provider.
* Provides support for username and password authentication, with support for roles list.
*/
public class HttpBasicAuthProvider extends SynchronousProvider implements AuthenticationProvider, OutboundSecurityProvider {
/**
* Configure this for outbound requests to override user to use.
*/
public static final String EP_PROPERTY_OUTBOUND_USER = "io.helidon.security.outbound.user";
/**
* Configure this for outbound requests to override password to use.
*/
public static final String EP_PROPERTY_OUTBOUND_PASSWORD = "io.helidon.security.outbound.password";
static final String HEADER_AUTHENTICATION_REQUIRED = "WWW-Authenticate";
static final String HEADER_AUTHENTICATION = "authorization";
static final String BASIC_PREFIX = "basic ";
private static final Logger LOGGER = Logger.getLogger(HttpBasicAuthProvider.class.getName());
private static final Pattern CREDENTIAL_PATTERN = Pattern.compile("(.*):(.*)");
private static final char[] EMPTY_PASSWORD = new char[0];
private final UserStore userStore;
private final String realm;
private final SubjectType subjectType;
private HttpBasicAuthProvider(Builder builder) {
this.userStore = builder.userStore;
this.realm = builder.realm;
this.subjectType = builder.subjectType;
}
/**
* Get a builder instance to construct a new security provider.
* Alternative approach is {@link #fromConfig(Config)} (or {@link HttpBasicAuthProvider#fromConfig(Config)}).
*
* @return builder to fluently construct Basic security provider
*/
public static Builder builder() {
return new Builder();
}
/**
* Load this provider from configuration.
*
* @param config Configuration located at this provider's configuration (e.g. child is either http-basic-auth or
* http-digest-auth)
* @return instance of provider configured from provided config
*/
public static HttpBasicAuthProvider fromConfig(Config config) {
return Builder.fromConfig(config).build();
}
private static OutboundSecurityResponse toBasicAuthOutbound(UserStore.User user) {
String b64 = Base64.getEncoder()
.encodeToString((user.getLogin() + ":" + new String(user.getPassword())).getBytes(StandardCharsets.UTF_8));
String basicAuthB64 = "basic " + b64;
return OutboundSecurityResponse
.withHeaders(CollectionsHelper.mapOf("Authorization", CollectionsHelper.listOf(basicAuthB64)));
}
@Override
public boolean isOutboundSupported(ProviderRequest providerRequest,
SecurityEnvironment outbondEnv,
EndpointConfig outboundEp) {
// explicitly overridden username and/or password
if (outboundEp.getAttributeNames().contains(EP_PROPERTY_OUTBOUND_USER)) {
return true;
}
SecurityContext secContext = providerRequest.getContext();
boolean userSupported = secContext.getUser()
.map(user -> user.getPrivateCredential(UserStore.User.class).isPresent()).orElse(false);
boolean serviceSupported = secContext.getService()
.map(user -> user.getPrivateCredential(UserStore.User.class).isPresent()).orElse(false);
return userSupported || serviceSupported;
}
@Override
protected OutboundSecurityResponse syncOutbound(ProviderRequest providerRequest,
SecurityEnvironment outboundEnv,
EndpointConfig outboundEp) {
// first resolve user to use
Optional