/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.controller;
import java.net.InetAddress;
import java.security.PrivilegedActionException;
import org.jboss.as.controller.security.ControllerPermission;
import org.jboss.as.core.security.AccessMechanism;
import org.wildfly.security.auth.server.SecurityDomain;
import org.wildfly.security.auth.server.SecurityIdentity;
import org.wildfly.security.manager.WildFlySecurityManager;
/**
* The context used to store state related to access control and auditing for the current invocation.
*
* @author <a href="mailto:darran.lofthouse@jboss.com">Darran Lofthouse</a>
*/
public class AccessAuditContext {
private static ThreadLocal<AccessAuditContext> contextThreadLocal = new ThreadLocal<AccessAuditContext>();
private final SecurityIdentity securityIdentity;
private final InetAddress remoteAddress;
private String domainUuid;
private AccessMechanism accessMechanism;
private boolean domainRollout;
private AccessAuditContext(final SecurityIdentity securityIdentity, final InetAddress remoteAddress, final AccessAuditContext previous) {
// This can only be instantiated as part of the doAs call.
this.securityIdentity = securityIdentity;
// The address would be set on the first context in the stack so use it.
this.remoteAddress = previous != null ? previous.remoteAddress : remoteAddress;
if (previous != null) {
domainUuid = previous.domainUuid;
accessMechanism = previous.accessMechanism;
domainRollout = previous.domainRollout;
}
}
/**
* Get the {@link SecurityIdentity} associated with this {@link AccessAuditContext}.
*
* This provides a way for the {@link SecurityIdentity} to be passed without the underlying {@link SecurityDomain} being known.
*
* @return the {@link SecurityIdentity} associated with this {@link AccessAuditContext}.
*/
public SecurityIdentity getSecurityIdentity() {
return securityIdentity;
}
/**
* Get the remote address of the caller.
*
* @return the remote address of the caller.
*/
public InetAddress getRemoteAddress() {
return remoteAddress;
}
/**
* Gets the unique identifier for a multi-domain-process operation.
*
* @return the identifier, or {@code null} if this context does not relate to a multi-domain-process operation
*/
public String getDomainUuid() {
return domainUuid;
}
public void setDomainUuid(String domainUuid) {
this.domainUuid = domainUuid;
}
/**
* Gets the mechanism via which the user initiated the access.
*
* @return the mechanism, or {@code null} if the access was initiated internally
*/
public AccessMechanism getAccessMechanism() {
return accessMechanism;
}
public void setAccessMechanism(AccessMechanism accessMechanism) {
this.accessMechanism = accessMechanism;
}
/**
* Gets whether this context relates to a secondary request initiated by a remote Host Controller
* process as part of its rollout of an operation initiated on that process.
*
* @return {@code true} if this context relates to a remotely coordinated multi-process domain operation
*/
public boolean isDomainRollout() {
return domainRollout;
}
public void setDomainRollout(boolean domainRollout) {
this.domainRollout = domainRollout;
}
/**
* Obtain the current {@link AccessAuditContext} or {@code null} if none currently set.
*
* @return The current {@link AccessAuditContext}
* @deprecated Internal use, will be changed without warning at any time.
*/
@Deprecated
public static AccessAuditContext currentAccessAuditContext() {
if (WildFlySecurityManager.isChecking()) {
System.getSecurityManager().checkPermission(ControllerPermission.GET_CURRENT_ACCESS_AUDIT_CONTEXT);
}
return contextThreadLocal.get();
}
/**
* Perform work with a new {@code AccessAuditContext} as a particular {@code SecurityIdentity}
* @param securityIdentity the {@code SecurityIdentity} that the specified {@code action} will run as. May be {@code null}
* @param remoteAddress the remote address of the caller.
* @param action the work to perform. Cannot be {@code null}
* @param <T> the type of teh return value
* @return the value returned by the PrivilegedAction's <code>run</code> method
*
* @exception NullPointerException if the specified
* <code>PrivilegedExceptionAction</code> is
* <code>null</code>.
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
*/
public static <T> T doAs(final SecurityIdentity securityIdentity, final InetAddress remoteAddress, final java.security.PrivilegedAction<T> action) {
final AccessAuditContext previous = contextThreadLocal.get();
try {
contextThreadLocal.set(new AccessAuditContext(securityIdentity, remoteAddress, previous));
return securityIdentity != null ? securityIdentity.runAs(action) : action.run();
} finally {
contextThreadLocal.set(previous);
}
}
/**
* Perform work with a new {@code AccessAuditContext} as a particular {@code SecurityIdentity}
* @param securityIdentity the {@code SecurityIdentity} that the specified {@code action} will run as. May be {@code null}
* @param remoteAddress the remote address of the caller.
* @param action the work to perform. Cannot be {@code null}
* @param <T> the type of teh return value
* @return the value returned by the PrivilegedAction's <code>run</code> method
*
* @exception java.security.PrivilegedActionException if the
* <code>PrivilegedExceptionAction.run</code>
* method throws a checked exception.
*
* @exception NullPointerException if the specified
* <code>PrivilegedExceptionAction</code> is
* <code>null</code>.
*
* @exception SecurityException if the caller does not have permission
* to invoke this method.
*/
public static <T> T doAs(SecurityIdentity securityIdentity, InetAddress remoteAddress, java.security.PrivilegedExceptionAction<T> action)
throws java.security.PrivilegedActionException {
final AccessAuditContext previous = contextThreadLocal.get();
try {
contextThreadLocal.set(new AccessAuditContext(securityIdentity, remoteAddress, previous));
if (securityIdentity != null) {
return securityIdentity.runAs(action);
} else try {
return action.run();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new PrivilegedActionException(e);
}
} finally {
contextThreadLocal.set(previous);
}
}
}