/*
* JBoss, Home of Professional Open Source.
* Copyright 2016 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* 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 org.jboss.as.controller.access.management;
import java.util.List;
import java.util.function.Supplier;
import org.jboss.as.controller.AccessAuditContext;
import org.wildfly.security.auth.principal.AnonymousPrincipal;
import org.wildfly.security.auth.server.RealmUnavailableException;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.auth.server.SecurityRealm;
import org.wildfly.security.auth.server.ServerAuthenticationContext;
/**
* A management specific supplier of the {@link SecurityIdentity} for access to the {@code ModelController}.
*
* The identity will be selected by using the following checks: -
* TODO Elytron - Complete the list !!
*
* @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a>
*/
public class ManagementSecurityIdentitySupplier implements Supplier<SecurityIdentity> {
private final SecurityDomain anonymousSecurityDomain = SecurityDomain.builder()
.setDefaultRealmName("Empty")
.addRealm("Empty", SecurityRealm.EMPTY_REALM).build()
.build();
private volatile Supplier<SecurityDomain> configuredSecurityDomainSupplier;
private volatile List<Supplier<SecurityDomain>> inflowSecurityDomainSuppliers;
@Override
public SecurityIdentity get() {
SecurityIdentity securityIdentity = null;
SecurityDomain configuredSecurityDomain = configuredSecurityDomainSupplier != null ? configuredSecurityDomainSupplier.get() : null;
if (configuredSecurityDomain != null) {
securityIdentity = configuredSecurityDomain.getCurrentSecurityIdentity();
if (AnonymousPrincipal.getInstance().equals(securityIdentity.getPrincipal()) == false) {
return securityIdentity;
}
}
AccessAuditContext accessAuditContext = SecurityActions.currentAccessAuditContext();
if (accessAuditContext != null) {
securityIdentity = accessAuditContext.getSecurityIdentity();
if (securityIdentity != null) {
if (configuredSecurityDomain != null) {
ServerAuthenticationContext serverAuthenticationContext = SecurityActions.createServerAuthenticationContext(configuredSecurityDomain);
try {
if (serverAuthenticationContext.importIdentity(securityIdentity)) {
return serverAuthenticationContext.getAuthorizedIdentity();
}
} catch (RealmUnavailableException | IllegalStateException e) {
// TODO Elytron Not much we can do but we need to log this as it means the real identity has been lost
// and we have no way to recover it.
// Final fallback for when we have no security ready.
return anonymousSecurityDomain.getAnonymousSecurityIdentity();
}
} else {
// TODO Elytron - For this fall though we want to check that the identity was from a wrapped realm.
return securityIdentity;
}
}
}
if (inflowSecurityDomainSuppliers != null && configuredSecurityDomain != null) {
for (Supplier<SecurityDomain> inflowSupplier : inflowSecurityDomainSuppliers) {
SecurityDomain current = inflowSupplier.get();
if (current != null) {
securityIdentity = current.getCurrentSecurityIdentity();
if (AnonymousPrincipal.getInstance().equals(securityIdentity.getPrincipal()) == false) {
ServerAuthenticationContext serverAuthenticationContext = SecurityActions.createServerAuthenticationContext(configuredSecurityDomain);
try {
if (serverAuthenticationContext.importIdentity(securityIdentity)) {
return serverAuthenticationContext.getAuthorizedIdentity();
}
} catch (RealmUnavailableException | IllegalStateException e) {
// Ignored, we may have more domains to attempt to inflow from and a final fall back to anonymous below.
}
}
}
}
}
// Final fallback for when we have no security ready.
return anonymousSecurityDomain.getAnonymousSecurityIdentity();
}
public void setConfiguredSecurityDomainSupplier(Supplier<SecurityDomain> configuredSecurityDomainSupplier) {
this.configuredSecurityDomainSupplier = configuredSecurityDomainSupplier;
}
public void setInflowSecurityDomainSuppliers(List<Supplier<SecurityDomain>> inflowSecurityDomainSuppliers) {
this.inflowSecurityDomainSuppliers = inflowSecurityDomainSuppliers;
}
}