/*
* RHQ Management Platform
* Copyright (C) 2005-2011 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.enterprise.server.naming.context;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NameClassPair;
import javax.naming.NameParser;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import org.rhq.enterprise.server.AllowRhqServerInternalsAccessPermission;
/**
* This is the "meat" of the RHQ's secured JNDI access. This {@link Context} decorator
* applied security checks in each method (lookups, (un)bindings, etc).
* <p>
* The security check consists of checking if the current callstack has the {@link AllowRhqServerInternalsAccessPermission}.
* <p>
* This decorator applies the security check on any JNDI name without a scheme and
* on any name that has a scheme listed in the {@link #checkedSchemes} list supplied
* in the constructor.
*
* @author Lukas Krejci
*/
public class AccessCheckingContextDecorator implements Context, ContextDecorator, Serializable {
private static final long serialVersionUID = 1L;
private static final AllowRhqServerInternalsAccessPermission PERM = new AllowRhqServerInternalsAccessPermission();
private Context original;
private List<String> checkedSchemes;
public AccessCheckingContextDecorator(String... checkedSchemes) {
this.checkedSchemes = Arrays.asList(checkedSchemes);
}
public AccessCheckingContextDecorator(Context original, String... checkedSchemes) {
this.original = original;
this.checkedSchemes = Arrays.asList(checkedSchemes);
}
public void init(Context ctx) {
this.original = ctx;
}
protected Context getOriginal() {
return original;
}
protected static void check() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(PERM);
}
private void checkScheme(String scheme) {
if (scheme == null || checkedSchemes.contains(scheme)) {
check();
}
}
protected void check(String name) {
checkScheme(getURLScheme(name));
}
protected void check(Name name) {
if (name.size() == 0) {
check();
} else {
String first = name.get(0);
checkScheme(getURLScheme(first));
}
}
public Object lookup(Name name) throws NamingException {
check(name);
return original.lookup(name);
}
public Object lookup(String name) throws NamingException {
check(name);
return original.lookup(name);
}
public void bind(Name name, Object obj) throws NamingException {
check(name);
original.bind(name, obj);
}
public void bind(String name, Object obj) throws NamingException {
check(name);
original.bind(name, obj);
}
public void rebind(Name name, Object obj) throws NamingException {
check(name);
original.rebind(name, obj);
}
public void rebind(String name, Object obj) throws NamingException {
check(name);
original.rebind(name, obj);
}
public void unbind(Name name) throws NamingException {
check(name);
original.unbind(name);
}
public void unbind(String name) throws NamingException {
check(name);
original.unbind(name);
}
public void rename(Name oldName, Name newName) throws NamingException {
check(oldName);
check(newName);
original.rename(oldName, newName);
}
public void rename(String oldName, String newName) throws NamingException {
check(oldName);
check(newName);
original.rename(oldName, newName);
}
public NamingEnumeration<NameClassPair> list(Name name) throws NamingException {
check(name);
return original.list(name);
}
public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
check(name);
return original.list(name);
}
public NamingEnumeration<Binding> listBindings(Name name) throws NamingException {
check(name);
return original.listBindings(name);
}
public NamingEnumeration<Binding> listBindings(String name) throws NamingException {
check(name);
return original.listBindings(name);
}
public void destroySubcontext(Name name) throws NamingException {
check(name);
original.destroySubcontext(name);
}
public void destroySubcontext(String name) throws NamingException {
check(name);
original.destroySubcontext(name);
}
public Context createSubcontext(Name name) throws NamingException {
check(name);
return original.createSubcontext(name);
}
public Context createSubcontext(String name) throws NamingException {
check(name);
return original.createSubcontext(name);
}
public Object lookupLink(Name name) throws NamingException {
check(name);
return original.lookupLink(name);
}
public Object lookupLink(String name) throws NamingException {
check(name);
return original.lookupLink(name);
}
public NameParser getNameParser(Name name) throws NamingException {
check(name);
return original.getNameParser(name);
}
public NameParser getNameParser(String name) throws NamingException {
check(name);
return original.getNameParser(name);
}
public Name composeName(Name name, Name prefix) throws NamingException {
check(name);
return original.composeName(name, prefix);
}
public String composeName(String name, String prefix) throws NamingException {
check(name);
return original.composeName(name, prefix);
}
public Object addToEnvironment(String propName, Object propVal) throws NamingException {
check();
return original.addToEnvironment(propName, propVal);
}
public Object removeFromEnvironment(String propName) throws NamingException {
check();
return original.removeFromEnvironment(propName);
}
public Hashtable<?, ?> getEnvironment() throws NamingException {
check();
return original.getEnvironment();
}
public void close() throws NamingException {
check();
original.close();
}
public String getNameInNamespace() throws NamingException {
check();
return original.getNameInNamespace();
}
//copied from InitialContext
private static String getURLScheme(String str) {
int colon_posn = str.indexOf(':');
int slash_posn = str.indexOf('/');
if (colon_posn > 0 && (slash_posn == -1 || colon_posn < slash_posn))
return str.substring(0, colon_posn);
return null;
}
@Override
public int hashCode() {
return getOriginal() == null ? super.hashCode() : getOriginal().hashCode();
}
@Override
public boolean equals(Object o) {
return getOriginal() == null ? super.equals(o) : getOriginal().equals(o);
}
}