/**
* Copyright 2014 Lockheed Martin Corporation
*
* 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 streamflow.server.config;
import com.google.inject.AbstractModule;
import com.google.inject.name.Names;
import javax.servlet.ServletContext;
import streamflow.model.config.AuthConfig;
import streamflow.server.security.DatastoreRealm;
import streamflow.server.security.DatastoreRealmModule;
import streamflow.util.config.ConfigLoader;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.guice.web.ShiroWebModule;
import org.apache.shiro.realm.AuthorizingRealm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SecurityModule extends ShiroWebModule {
private static final Logger LOG = LoggerFactory.getLogger(SecurityModule.class);
public SecurityModule(ServletContext servletContext) {
super(servletContext);
}
@Override
protected final void configureShiroWeb() {
AuthConfig authConfig = ConfigLoader.getConfig().getAuth();
// Basic auth - change auth scheme to hide native browser basic auth dialog box
bindConstant().annotatedWith(Names.named("shiro.authcScheme")).to("Streamflow");
// 12 hour session timeout in milliseconds
bindConstant().annotatedWith(Names.named("shiro.globalSessionTimeout")).to(43200000L);
// Attempt to load the custom realm class/module and use defaults if necessary
Class<AuthorizingRealm> realmClass = loadRealmClass(authConfig);
AbstractModule realmModule = loadRealmModule(authConfig);
// Bind the provided realm to this Shiro context
bindRealm().to(realmClass);
// Install the realm module class to fulfill any dependencies required by the realm
install(realmModule);
// Only add security based filter settings if auth is enabled
if (authConfig.isEnabled()) {
addFilterChain("/logout/", LOGOUT);
addFilterChain("/api/security/**", ANON);
addFilterChain("/api/**", AUTHC_BASIC);
}
// All remaining resources should be anonymous
addFilterChain("/**", ANON);
}
protected Class<AuthorizingRealm> loadRealmClass(AuthConfig authConfig) {
Class realmClass = DatastoreRealm.class;
if (StringUtils.isNotBlank(authConfig.getRealmClass())) {
try {
LOG.info("Loading custom realm class: " + authConfig.getRealmClass());
Class loadedRealmClass = Thread.currentThread().getContextClassLoader()
.loadClass(authConfig.getRealmClass());
// Make sure the datastore module class is an actual Guice AbstractModule
if (AuthorizingRealm.class.isAssignableFrom(loadedRealmClass)) {
realmClass = loadedRealmClass;
LOG.info("Successfully loaded custom realm class: " + authConfig.getRealmClass());
} else {
LOG.error("The custom realm class does not extend AuthorizingRealm: {}",
authConfig.getRealmClass());
LOG.info("Using default DatastoreRealm implementation");
}
} catch (Exception ex) {
LOG.error("An exception occurred while loading the custom realm class", ex);
LOG.info("Using default DatastoreRealm implementation");
}
} else {
LOG.info("Using default DatastoreRealm implementation");
}
return realmClass;
}
protected AbstractModule loadRealmModule(AuthConfig authConfig) {
AbstractModule realmModule = new DatastoreRealmModule();
if (StringUtils.isNotBlank(authConfig.getModuleClass())) {
try {
LOG.info("Loading custom realm module: " + authConfig.getModuleClass());
Class datastoreModuleClass = Thread.currentThread().getContextClassLoader()
.loadClass(authConfig.getModuleClass());
// Make sure the datastore module class is an actual Guice AbstractModule
if (AbstractModule.class.isAssignableFrom(datastoreModuleClass)) {
realmModule = (AbstractModule) datastoreModuleClass.newInstance();
LOG.info("Successfully loaded custom realm module: " + authConfig.getModuleClass());
} else {
LOG.error("The provided custom realm module class does not extend AbstractModule: {}",
authConfig.getModuleClass());
LOG.info("Using default DatastoreRealmModule implementation");
}
} catch (Exception ex) {
LOG.error("An exception occurred while loading the custom realm module", ex);
LOG.info("Using default DatastoreRealmModule implementation");
}
} else {
LOG.info("Using default DatastoreRealmModule implementation");
}
return realmModule;
}
}