/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.dqp.internal.process;
import java.io.Serializable;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import javax.security.auth.Subject;
import org.teiid.adminapi.DataPolicy;
import org.teiid.adminapi.impl.SessionMetadata;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.client.BatchSerializer;
import org.teiid.client.security.SessionToken;
import org.teiid.core.util.PropertiesUtils;
import org.teiid.dqp.message.RequestID;
import org.teiid.jdbc.LocalProfile;
import org.teiid.logging.LogManager;
import org.teiid.metadata.MetadataFactory;
import org.teiid.query.metadata.SystemMetadata;
import org.teiid.query.metadata.TransformationMetadata;
import org.teiid.security.SecurityHelper;
public class DQPWorkContext implements Serializable {
private static final String TEIID_VDB = "teiid-vdb"; //$NON-NLS-1$
private static final String TEIID_SESSION = "teiid-session"; //$NON-NLS-1$
private static final long serialVersionUID = -6389893410233192977L;
private static final boolean longDatesTimes = PropertiesUtils.getBooleanProperty(System.getProperties(), "org.teiid.longDatesTimes", false); //$NON-NLS-1$
public enum Version {
SEVEN_1("07.01", (byte)0), //$NON-NLS-1$
SEVEN_3("07.03", (byte)0), //$NON-NLS-1$
SEVEN_4("07.04", (byte)0), //$NON-NLS-1$
EIGHT_0("08.00", (byte)(longDatesTimes?0:1)), //$NON-NLS-1$
EIGHT_2("08.02", (byte)2), //$NON-NLS-1$
EIGHT_4("08.04.00.CR3", (byte)2), //$NON-NLS-1$
EIGHT_6("08.06.00.Beta3", (byte)3), //$NON-NLS-1$
EIGHT_7("08.07.00.Beta2", (byte)3), //$NON-NLS-1$
EIGHT_10("08.10.00.Alpha3", BatchSerializer.VERSION_GEOMETRY); //$NON-NLS-1$
private String string;
private byte clientSerializationVersion;
private Version(String string, byte clientSerializationVersion) {
this.string = string;
this.clientSerializationVersion = clientSerializationVersion;
}
public byte getClientSerializationVersion() {
return clientSerializationVersion;
}
@Override
public String toString() {
return string;
}
private static TreeMap<String, Version> versionMap = new TreeMap<String, Version>();
static {
for (Version v : Version.values()) {
versionMap.put(v.toString(), v);
}
}
public static Version getVersion(String version) {
Map.Entry<String, Version> v = versionMap.floorEntry(version);
if (v == null) {
return SEVEN_1;
}
return v.getValue();
}
public static Version latest() {
return versionMap.lastEntry().getValue();
}
}
private static ThreadLocal<DQPWorkContext> CONTEXTS = new ThreadLocal<DQPWorkContext>() {
protected DQPWorkContext initialValue() {
return new DQPWorkContext();
}
};
public static DQPWorkContext getWorkContext() {
return CONTEXTS.get();
}
public static void setWorkContext(DQPWorkContext context) {
LogManager.removeMdc(TEIID_SESSION);
LogManager.removeMdc(TEIID_VDB);
if (context == null) {
CONTEXTS.remove();
} else {
if (context.session != null) {
LogManager.putMdc(TEIID_SESSION, context.session.getSessionId());
if (context.session.getVdb() != null) {
LogManager.putMdc(TEIID_VDB, context.session.getVdb().getFullName());
}
}
CONTEXTS.set(context);
}
}
private volatile SessionMetadata session = new SessionMetadata();
private String clientAddress;
private String clientHostname;
private SecurityHelper securityHelper;
private HashMap<String, DataPolicy> policies;
private boolean useCallingThread;
private Version clientVersion = Version.latest();
private boolean admin;
private MetadataFactory metadataFactory;
private transient LocalProfile connectionProfile = new LocalProfile();
private boolean local = true;
public DQPWorkContext() {
}
public boolean useCallingThread() {
return useCallingThread;
}
public void setUseCallingThread(boolean useCallingThread) {
this.useCallingThread = useCallingThread;
}
public SessionMetadata getSession() {
return session;
}
public void setSession(SessionMetadata session) {
this.session = session;
this.policies = null;
}
public void setSecurityHelper(SecurityHelper securityHelper) {
this.securityHelper = securityHelper;
}
public SecurityHelper getSecurityHelper() {
return securityHelper;
}
/**
* @return
*/
public String getUserName() {
return session.getUserName();
}
public Subject getSubject() {
return session.getSubject();
}
/**
* @return
*/
public String getVdbName() {
return session.getVDBName();
}
/**
* @return
*/
public String getVdbVersion() {
return session.getVDBVersion();
}
public String getSessionId() {
return this.session.getSessionId();
}
public String getAppName() {
return session.getApplicationName();
}
public RequestID getRequestID(long exeuctionId) {
return new RequestID(this.getSessionId(), exeuctionId);
}
public SessionToken getSessionToken() {
return session.getSessionToken();
}
public void setClientAddress(String clientAddress) {
this.clientAddress = clientAddress;
}
/**
* Get the client address from the socket transport - not as reported from the client
* @return
*/
public String getClientAddress() {
return clientAddress;
}
public void setClientHostname(String clientHostname) {
this.clientHostname = clientHostname;
}
/**
* Get the client hostname from the socket transport - not as reported from the client
* @return
*/
public String getClientHostname() {
return clientHostname;
}
public String getSecurityDomain() {
return this.session.getSecurityDomain();
}
public Object getSecurityContext() {
return session.getSecurityContext();
}
public void setSecurityContext(Object securityContext) {
session.setSecurityContext(securityContext);
}
public VDBMetaData getVDB() {
return session.getVdb();
}
public <V> V runInContext(Callable<V> callable) throws Throwable {
FutureTask<V> task = new FutureTask<V>(callable);
runInContext(task);
try {
return task.get();
} catch (ExecutionException e) {
throw e.getCause();
}
}
public void runInContext(final Runnable runnable) {
DQPWorkContext previous = DQPWorkContext.getWorkContext();
DQPWorkContext.setWorkContext(this);
Object previousSecurityContext = null;
if (securityHelper != null) {
previousSecurityContext = securityHelper.associateSecurityContext(this.getSecurityContext());
}
try {
runnable.run();
} finally {
if (securityHelper != null) {
securityHelper.associateSecurityContext(previousSecurityContext);
}
DQPWorkContext.setWorkContext(previous);
}
}
public HashMap<String, DataPolicy> getAllowedDataPolicies() {
if (this.policies == null) {
this.policies = new HashMap<String, DataPolicy>();
Set<String> userRoles = getUserRoles();
// get data roles from the VDB
VDBMetaData vdb = getVDB();
TransformationMetadata metadata = vdb.getAttachment(TransformationMetadata.class);
Collection<? extends DataPolicy> allPolicies = null;
if (metadata == null) {
allPolicies = vdb.getDataPolicies();
} else {
allPolicies = metadata.getPolicies().values();
}
for (DataPolicy policy : allPolicies) {
if (matchesPrincipal(userRoles, policy)) {
this.policies.put(policy.getName(), policy);
}
}
}
return this.policies;
}
public void setPolicies(HashMap<String, DataPolicy> policies) {
this.policies = policies;
}
private boolean matchesPrincipal(Set<String> userRoles, DataPolicy policy) {
if (policy.isAnyAuthenticated() && this.getSubject() != null) {
return true;
}
return !Collections.disjoint(policy.getMappedRoleNames(), userRoles);
}
private Set<String> getUserRoles() {
return getUserRoles(getSubject());
}
public static Set<String> getUserRoles(Subject subject) {
if (subject == null) {
return Collections.emptySet();
}
Set<String> roles = new HashSet<String>();
Set<Principal> principals = subject.getPrincipals();
for(Principal p: principals) {
// this JBoss specific, but no code level dependencies
if ((p instanceof Group) && p.getName().equals("Roles")){ //$NON-NLS-1$
Group g = (Group)p;
Enumeration<? extends Principal> rolesPrinciples = g.members();
while(rolesPrinciples.hasMoreElements()) {
roles.add(rolesPrinciples.nextElement().getName());
}
}
}
return roles;
}
public Version getClientVersion() {
return clientVersion;
}
public void setClientVersion(Version clientVersion) {
this.clientVersion = clientVersion;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public boolean isAdmin() {
return admin;
}
public MetadataFactory getTempMetadataFactory() {
if (this.metadataFactory == null) {
this.metadataFactory = new MetadataFactory("temp", 1, "temp", SystemMetadata.getInstance().getRuntimeTypeMap(), null, null); //$NON-NLS-1$ //$NON-NLS-2$
}
return this.metadataFactory;
}
public void setConnectionProfile(LocalProfile connectionProfile) {
this.connectionProfile = connectionProfile;
}
public LocalProfile getConnectionProfile() {
return connectionProfile;
}
public boolean isLocal() {
return this.local;
}
public DQPWorkContext local(boolean b) {
this.local = b;
return this;
}
}