Add SecurityProvider implementation basd on Apache Shiro
parent
78b1b36e71
commit
3bd6c597fd
|
@ -47,7 +47,9 @@ import javax.management.ObjectName;
|
|||
import javax.management.remote.JMXConnectorServer;
|
||||
import javax.management.remote.JMXConnectorServerFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import net.openesb.standalone.security.auth.login.CustomJMXAuthenticator;
|
||||
import javax.naming.Context;
|
||||
import net.openesb.standalone.security.SecurityProviderImpl;
|
||||
import net.openesb.standalone.security.auth.login.JMXauthenticator;
|
||||
//import net.openesb.standalone.node.Node;
|
||||
//import net.openesb.standalone.node.NodeBuilder;
|
||||
import net.openesb.standalone.settings.ImmutableSettings;
|
||||
|
@ -114,16 +116,19 @@ public class JSEJBIFramework
|
|||
|
||||
mLog.log(Level.FINE, "Trying to load configuration from {0}", configFile);
|
||||
|
||||
Map configurations = null;
|
||||
|
||||
try {
|
||||
Yaml yaml = new Yaml(new Constructor(), new Representer(), new DumperOptions(),
|
||||
new Resolver() {
|
||||
@Override
|
||||
protected void addImplicitResolvers() {
|
||||
//super.addImplicitResolvers(); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
});
|
||||
InputStream input = new FileInputStream(new File(configFile));
|
||||
settings = new ImmutableSettings((Map) yaml.load(input));
|
||||
configurations = (Map) yaml.load(input);
|
||||
|
||||
settings = new ImmutableSettings(configurations);
|
||||
mLog.log(Level.FINE, "Configuration loaded from {0}", configFile);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
mLog.log(Level.WARNING, "Unable to load configuration file {0}. Default configuration will be used.", configFile);
|
||||
|
@ -135,8 +140,9 @@ public class JSEJBIFramework
|
|||
settings.get(INSTANCE_NAME, DEFAULT_INSTANCE_NAME),
|
||||
settings.getAsInt(CONNECTOR_PORT, DEFAULT_CONNECTOR_PORT));
|
||||
|
||||
// Do it in the main thread, not during an RMI connection
|
||||
// SecurityProvider.getSecurityProvider();
|
||||
mPlatformContext.setSecurityProvider(
|
||||
new SecurityProviderImpl(
|
||||
(Map<String,Map<String,String>>) configurations.get("realm")));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -270,9 +276,9 @@ public class JSEJBIFramework
|
|||
// Create an RMI registry instance to hold the JMX connector server
|
||||
mRegistry = LocateRegistry.createRegistry(port);
|
||||
|
||||
map.put(JMXConnectorServer.AUTHENTICATOR, new CustomJMXAuthenticator(
|
||||
map.put(JMXConnectorServer.AUTHENTICATOR, new JMXauthenticator(
|
||||
mPlatformContext.getSecurityProvider()));
|
||||
map.put("java.naming.factory.initial", RegistryContextFactory.class.getName());
|
||||
map.put(Context.INITIAL_CONTEXT_FACTORY, RegistryContextFactory.class.getName());
|
||||
map.put("com.sun.management.jmxremote.authenticate", Boolean.TRUE.toString());
|
||||
|
||||
// Create and start the connector server
|
||||
|
|
|
@ -423,8 +423,14 @@ public class JSEPlatformContext implements com.sun.jbi.platform.PlatformContext
|
|||
Logger.getLogger(JBI_LOGGER_NAME).setLevel(level);
|
||||
}
|
||||
|
||||
private SecurityProvider securityProvider;
|
||||
|
||||
public void setSecurityProvider(SecurityProvider securityProvider) {
|
||||
this.securityProvider = securityProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecurityProvider getSecurityProvider() {
|
||||
return new SecurityProviderImpl();
|
||||
return securityProvider;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,11 @@
|
|||
<artifactId>openesb-standalone-naming</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.open-esb.runtime.standalone</groupId>
|
||||
<artifactId>openesb-standalone-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Atomikos -->
|
||||
<dependency>
|
||||
|
@ -101,6 +106,13 @@
|
|||
<version>5.0.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache Shiro -->
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<version>${shiro.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- OpenESB REST API & Web Console -->
|
||||
<dependency>
|
||||
<groupId>net.open-esb</groupId>
|
||||
|
|
|
@ -96,6 +96,7 @@
|
|||
<include>org.apache.tomcat:tomcat-juli</include>
|
||||
<include>org.apache.tomcat:tomcat-catalina</include>
|
||||
<include>org.yaml:snakeyaml</include>
|
||||
<include>org.apache.shiro:shiro-core</include>
|
||||
</includes>
|
||||
<outputDirectory>lib/ext</outputDirectory>
|
||||
<useProjectArtifact>false</useProjectArtifact>
|
||||
|
@ -108,6 +109,7 @@
|
|||
<include>net.open-esb.runtime.standalone:openesb-standalone-framework</include>
|
||||
<include>net.open-esb.runtime.standalone:openesb-standalone-bootstrap</include>
|
||||
<include>net.open-esb.runtime.standalone:openesb-standalone-naming</include>
|
||||
<include>net.open-esb.runtime.standalone:openesb-standalone-security</include>
|
||||
</includes>
|
||||
<binaries>
|
||||
<includeDependencies>false</includeDependencies>
|
||||
|
|
|
@ -10,9 +10,9 @@ import javax.security.auth.Subject;
|
|||
import net.openesb.security.AuthenticationException;
|
||||
import net.openesb.security.AuthenticationToken;
|
||||
import net.openesb.security.SecurityProvider;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.mgt.DefaultSecurityManager;
|
||||
import org.apache.shiro.realm.text.PropertiesRealm;
|
||||
import net.openesb.standalone.security.realm.Realm;
|
||||
import net.openesb.standalone.security.realm.RealmBuilder;
|
||||
import net.openesb.standalone.security.realm.shiro.ShiroAuthenticator;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -21,59 +21,67 @@ import org.apache.shiro.realm.text.PropertiesRealm;
|
|||
*/
|
||||
public class SecurityProviderImpl implements SecurityProvider {
|
||||
|
||||
private Logger mLog =
|
||||
private final Logger mLog =
|
||||
Logger.getLogger(this.getClass().getPackage().getName());
|
||||
|
||||
private final Map <String, org.apache.shiro.mgt.SecurityManager> securityManagers =
|
||||
new HashMap<String, org.apache.shiro.mgt.SecurityManager>();
|
||||
private final Map<String, Realm> realms = new HashMap<String, Realm>();
|
||||
private final ShiroAuthenticator authenticator = new ShiroAuthenticator();
|
||||
private String adminRealmName = null;
|
||||
|
||||
public SecurityProviderImpl() {
|
||||
this.init();
|
||||
public SecurityProviderImpl(Map<String, Map<String, String>> realmsConfiguration) {
|
||||
this.init(realmsConfiguration);
|
||||
this.validate();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mLog.log(Level.INFO, "Loading Realms from configuration.");
|
||||
private void init(Map<String, Map<String, String>> realmsConfiguration) {
|
||||
if (realmsConfiguration != null) {
|
||||
mLog.log(Level.INFO, "Loading realms from configuration file.");
|
||||
|
||||
PropertiesRealm propertiesRealm = new PropertiesRealm();
|
||||
propertiesRealm.setResourcePath("/Users/david/test.properties");
|
||||
propertiesRealm.init();
|
||||
for(Map.Entry<String, Map<String, String>> realmConfig : realmsConfiguration.entrySet()) {
|
||||
Realm realm = RealmBuilder.
|
||||
realmBuilder().
|
||||
build(realmConfig.getKey(), realmConfig.getValue());
|
||||
|
||||
securityManagers.put("admin-realm", new DefaultSecurityManager(propertiesRealm));
|
||||
realms.put(realmConfig.getKey(), realm);
|
||||
}
|
||||
} else {
|
||||
mLog.log(Level.WARNING, "No realm defined !");
|
||||
}
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
for(Realm realm : realms.values()) {
|
||||
authenticator.loadRealm(realm);
|
||||
|
||||
if (realm.isAdmin()) {
|
||||
if (adminRealmName == null) {
|
||||
adminRealmName = realm.getName();
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"Admin realm already defined: " + adminRealmName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getRealms() {
|
||||
return Collections.unmodifiableSet(
|
||||
securityManagers.keySet());
|
||||
realms.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAdminRealm() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
return adminRealmName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(String realmName) {
|
||||
return securityManagers.containsKey(realmName);
|
||||
return realms.containsKey(realmName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject login(String realmName, AuthenticationToken authenticationToken) throws AuthenticationException {
|
||||
org.apache.shiro.mgt.SecurityManager securityManager = securityManagers.get(realmName);
|
||||
org.apache.shiro.subject.Subject currentUser =
|
||||
new org.apache.shiro.subject.Subject.Builder(securityManager).buildSubject();
|
||||
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(
|
||||
(String) authenticationToken.getPrincipal(),
|
||||
(char []) authenticationToken.getCredentials());
|
||||
|
||||
try {
|
||||
currentUser.login(token);
|
||||
|
||||
Subject subject = new Subject();
|
||||
return subject;
|
||||
} catch (org.apache.shiro.authc.AuthenticationException ae) {
|
||||
throw new AuthenticationException(ae.getMessage());
|
||||
}
|
||||
return authenticator.authenticate(realmName, authenticationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ import net.openesb.security.UsernamePasswordToken;
|
|||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public class CustomJMXAuthenticator implements JMXAuthenticator {
|
||||
public class JMXauthenticator implements JMXAuthenticator {
|
||||
|
||||
private final SecurityProvider securityProvider;
|
||||
|
||||
public CustomJMXAuthenticator(final SecurityProvider securityProvider) {
|
||||
public JMXauthenticator(final SecurityProvider securityProvider) {
|
||||
this.securityProvider = securityProvider;
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package net.openesb.standalone.security.realm;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public abstract class AbstractRealm implements Realm {
|
||||
|
||||
private String realmName;
|
||||
private boolean admin = false;
|
||||
|
||||
protected AbstractRealm() {
|
||||
}
|
||||
|
||||
protected AbstractRealm(String realmName) {
|
||||
this.realmName = realmName;
|
||||
}
|
||||
|
||||
public boolean isAdmin() {
|
||||
return admin;
|
||||
}
|
||||
|
||||
public void setAdmin(boolean admin) {
|
||||
this.admin = admin;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return realmName;
|
||||
}
|
||||
|
||||
public void setName(String realmName) {
|
||||
this.realmName = realmName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package net.openesb.standalone.security.realm;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public interface Realm {
|
||||
|
||||
void setName(String name);
|
||||
|
||||
String getName();
|
||||
|
||||
boolean isAdmin();
|
||||
|
||||
void setAdmin(boolean isAdmin);
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package net.openesb.standalone.security.realm;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public final class RealmBuilder {
|
||||
|
||||
public static RealmBuilder realmBuilder() {
|
||||
return new RealmBuilder();
|
||||
}
|
||||
|
||||
public Realm build(String realmName, Map<String, String> properties) {
|
||||
ServiceLoader<RealmHandler> handlers = ServiceLoader.load(RealmHandler.class);
|
||||
for(RealmHandler handler : handlers) {
|
||||
if (handler.canHandle(realmName)) {
|
||||
Realm realm = handler.create(properties);
|
||||
realm.setName(realmName);
|
||||
|
||||
return realm;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Unable to create realm " + realmName +
|
||||
" : no handler found !");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package net.openesb.standalone.security.realm;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public interface RealmHandler<T extends Realm> {
|
||||
|
||||
boolean canHandle(String type);
|
||||
|
||||
T create(Map<String, String> properties);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package net.openesb.standalone.security.realm.impl;
|
||||
|
||||
import net.openesb.standalone.security.realm.AbstractRealm;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public class PropertiesRealm extends AbstractRealm {
|
||||
|
||||
private String path;
|
||||
|
||||
private boolean reload = false;
|
||||
|
||||
/**
|
||||
* Unit: seconds
|
||||
*/
|
||||
private int reloadInterval;
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public boolean isReload() {
|
||||
return reload;
|
||||
}
|
||||
|
||||
public void setReload(boolean reload) {
|
||||
this.reload = reload;
|
||||
}
|
||||
|
||||
public int getReloadInterval() {
|
||||
return reloadInterval;
|
||||
}
|
||||
|
||||
public void setReloadInterval(int reloadInterval) {
|
||||
this.reloadInterval = reloadInterval;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package net.openesb.standalone.security.realm.impl;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import net.openesb.standalone.security.realm.RealmHandler;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public class PropertiesRealmHandler implements RealmHandler<PropertiesRealm> {
|
||||
|
||||
private final Logger mLog =
|
||||
Logger.getLogger(this.getClass().getPackage().getName());
|
||||
|
||||
private final static String PROPERTIES_REALM = "properties";
|
||||
|
||||
private final static String PROPERTY_PATH = "file";
|
||||
private final static String PROPERTY_RELOAD_ENABLE = "reload";
|
||||
private final static String PROPERTY_RELOAD_INTERVAL = "interval";
|
||||
|
||||
@Override
|
||||
public boolean canHandle(String type) {
|
||||
return PROPERTIES_REALM.equalsIgnoreCase(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertiesRealm create(Map<String, String> properties) {
|
||||
String file = properties.get(PROPERTY_PATH);
|
||||
mLog.log(Level.INFO, "Creating properties realm using file: {0}", file);
|
||||
|
||||
File propertyFile = new File(file);
|
||||
if (! propertyFile.exists()) {
|
||||
mLog.log(Level.SEVERE, "Properties realm, invalid path: {0}",
|
||||
propertyFile.getAbsolutePath());
|
||||
throw new IllegalStateException("Properties realm, invalid path: " +
|
||||
propertyFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
boolean reload = Boolean.parseBoolean(properties.get(PROPERTY_RELOAD_ENABLE));
|
||||
PropertiesRealm propertiesRealm = new PropertiesRealm();
|
||||
propertiesRealm.setPath(propertyFile.getAbsolutePath());
|
||||
|
||||
if (reload) {
|
||||
String sInterval = properties.get(PROPERTY_RELOAD_INTERVAL);
|
||||
try {
|
||||
int interval = Integer.parseInt(sInterval);
|
||||
propertiesRealm.setReloadInterval(interval);
|
||||
} catch (NumberFormatException nfe) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return propertiesRealm;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package net.openesb.standalone.security.realm.shiro;
|
||||
|
||||
import org.apache.shiro.realm.text.PropertiesRealm;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public class PropertiesRealmConverter implements
|
||||
RealmConverter<net.openesb.standalone.security.realm.impl.PropertiesRealm, PropertiesRealm> {
|
||||
|
||||
@Override
|
||||
public PropertiesRealm convert(net.openesb.standalone.security.realm.impl.PropertiesRealm realm) {
|
||||
PropertiesRealm cRealm = new PropertiesRealm();
|
||||
cRealm.setResourcePath(realm.getPath());
|
||||
|
||||
if (realm.isReload()) {
|
||||
cRealm.setReloadIntervalSeconds(realm.getReloadInterval());
|
||||
}
|
||||
|
||||
return cRealm;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package net.openesb.standalone.security.realm.shiro;
|
||||
|
||||
import net.openesb.standalone.security.realm.Realm;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public interface RealmConverter<T extends Realm, S extends org.apache.shiro.realm.Realm> {
|
||||
|
||||
S convert(T realm);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package net.openesb.standalone.security.realm.shiro;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
import javax.security.auth.Subject;
|
||||
import net.openesb.security.AuthenticationException;
|
||||
import net.openesb.security.AuthenticationToken;
|
||||
import net.openesb.standalone.security.realm.Realm;
|
||||
import net.openesb.standalone.security.realm.impl.PropertiesRealm;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.mgt.DefaultSecurityManager;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author David BRASSELY (brasseld at gmail.com)
|
||||
* @author OpenESB Community
|
||||
*/
|
||||
public class ShiroAuthenticator {
|
||||
|
||||
private final Logger mLog =
|
||||
Logger.getLogger(this.getClass().getPackage().getName());
|
||||
|
||||
private final Map <String, org.apache.shiro.mgt.SecurityManager> securityManagers =
|
||||
new HashMap<String, org.apache.shiro.mgt.SecurityManager>();
|
||||
|
||||
public void loadRealm(Realm realm) {
|
||||
//TODO: find a way to automate the convertion
|
||||
org.apache.shiro.realm.Realm sRealm = new PropertiesRealmConverter().convert((PropertiesRealm)realm);
|
||||
|
||||
DefaultSecurityManager manager = new DefaultSecurityManager(sRealm);
|
||||
securityManagers.put(realm.getName(), manager);
|
||||
}
|
||||
|
||||
public Subject authenticate(String realmName, AuthenticationToken authenticationToken)
|
||||
throws AuthenticationException {
|
||||
org.apache.shiro.mgt.SecurityManager securityManager = securityManagers.get(realmName);
|
||||
org.apache.shiro.subject.Subject currentUser =
|
||||
new org.apache.shiro.subject.Subject.Builder(securityManager).buildSubject();
|
||||
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(
|
||||
(String) authenticationToken.getPrincipal(),
|
||||
(char []) authenticationToken.getCredentials());
|
||||
|
||||
try {
|
||||
currentUser.login(token);
|
||||
|
||||
Subject subject = new Subject();
|
||||
return subject;
|
||||
} catch (org.apache.shiro.authc.AuthenticationException ae) {
|
||||
throw new AuthenticationException(ae.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
net.openesb.standalone.security.realm.shiro.PropertiesRealmHandler
|
Loading…
Reference in New Issue