org.springframework.beans.factory.config,
org.springframework.ldap.core.support,
org.springframework.security,
+ org.springframework.security.adapters;specification-version="2.0.4.A",
org.springframework.security.ldap,
org.springframework.security.ldap.populator,
org.springframework.security.providers,
org.springframework.security.providers.ldap,
org.springframework.security.providers.ldap.authenticator,
+ org.springframework.security.providers.rememberme;specification-version="2.0.4.A",
org.springframework.security.userdetails,
org.springframework.security.userdetails.ldap
Bundle-Name: Security Manager LDAP
\r
<service ref="securityDao" interface="org.argeo.security.ArgeoSecurityDao"\r
context-class-loader="service-provider" />\r
+ <service ref="userDetailsManager"\r
+ interface="org.springframework.security.userdetails.UserDetailsService"\r
+ context-class-loader="service-provider" />\r
\r
<list id="userNatureMappers" interface="org.argeo.security.ldap.UserNatureMapper"\r
cardinality="0..N" />\r
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
- <property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<value>osgibundle:ldap.properties
</value>
<bean id="_authenticationManager" class="org.springframework.security.providers.ProviderManager">
<property name="providers">
<list>
+ <bean class="org.springframework.security.adapters.AuthByAdapterProvider">
+ <property name="key" value="${argeo.security.systemKey}" />
+ </bean>
+ <bean
+ class="org.springframework.security.providers.rememberme.RememberMeAuthenticationProvider">
+ <property name="key" value="${argeo.security.systemKey}" />
+ </bean>
<ref bean="authenticationProvider" />
</list>
</property>
<property name="userNatureMappers" ref="userNatureMappers" />
</bean>
+ <bean id="userDetailsManager" factory-bean="securityDao"
+ factory-method="getUserDetailsManager">
+ </bean>
+
<bean id="ldapAuthenticator"
class="org.springframework.security.providers.ldap.authenticator.PasswordComparisonAuthenticator">
<constructor-arg ref="contextSource" />
argeo.ldap.port=10389
argeo.ldap.manager.userdn=uid=admin,ou=system
argeo.ldap.manager.password=secret
+
+argeo.security.systemKey=argeo
Bundle-SymbolicName: org.argeo.security.services
Bundle-Version: 0.1.3.SNAPSHOT
Import-Package: org.argeo.security,
- org.argeo.security.core
+ org.argeo.security.core,
+ org.springframework.beans.factory.config;specification-version="2.5.6.SEC01",
+ org.springframework.security;specification-version="2.0.4.A"
Bundle-Name: Security Services
\r
<service ref="securityService" interface="org.argeo.security.ArgeoSecurityService" />\r
\r
- <reference id="securityDao" interface="org.argeo.security.ArgeoSecurityDao"\r
- />\r
+ <reference id="securityDao" interface="org.argeo.security.ArgeoSecurityDao" />\r
+ <reference id="authenticationManager" interface="org.springframework.security.AuthenticationManager" />\r
</beans:beans>
\ No newline at end of file
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
+ <bean
+ class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+ <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
+ <property name="locations">
+ <value>osgibundle:security.properties
+ </value>
+ </property>
+ </bean>
+
<bean id="securityService" class="org.argeo.security.core.DefaultSecurityService">
<property name="securityDao" ref="securityDao" />
+ <property name="authenticationManager" ref="authenticationManager" />
+ <property name="systemAuthenticationKey" value="${argeo.security.systemKey}" />
</bean>
</beans>
\ No newline at end of file
--- /dev/null
+argeo.security.systemKey=argeo
org.springframework.security,
org.springframework.security.config,
org.springframework.security.ui,
+ org.springframework.security.ui.rememberme;specification-version="2.0.4.A",
org.springframework.security.ui.webapp,
+ org.springframework.security.userdetails;specification-version="2.0.4.A",
org.springframework.web.context,
org.springframework.web.context.support,
org.springframework.web.filter,
class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"
lazy-init="false">
<property name="contextOverride" value="true" />
- <property name="ignoreUnresolvablePlaceholders" value="true" />
</bean>
</beans>
\ No newline at end of file
\r
<reference id="_authenticationManager"\r
interface="org.springframework.security.AuthenticationManager" />\r
+ <reference id="userDetailsService"\r
+ interface="org.springframework.security.userdetails.UserDetailsService" />\r
\r
<reference id="securityService" interface="org.argeo.security.ArgeoSecurityService" />\r
\r
<list id="objectFactories" interface="org.argeo.server.json.JsonObjectFactory"\r
cardinality="0..N" />\r
\r
-<!-- \r
- <service ref="authenticationProcessingFilterEntryPoint"\r
- interface="org.springframework.security.ui.AuthenticationEntryPoint" /> -->\r
+ <!--\r
+ <service ref="authenticationProcessingFilterEntryPoint"\r
+ interface="org.springframework.security.ui.AuthenticationEntryPoint"\r
+ />\r
+ -->\r
</beans:beans>
\ No newline at end of file
logout-success-url="/getCredentials.ria" />
<security:anonymous username="anonymous"
granted-authority="ROLE_ANONYMOUS" />
+ <security:remember-me key="argeo" services-ref="rememberMeServices" />
</security:http>
+ <bean id="rememberMeServices" class="org.argeo.security.mvc.ArgeoRememberMeServices">
+ <property name="alwaysRemember" value="true" />
+ <property name="userDetailsService" ref="userDetailsService" />
+ <property name="key" value="${argeo.security.systemKey}" />
+ </bean>
+
+
<bean id="authenticationProcessingFilter"
class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
<security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />
<url-pattern>/*</url-pattern>
</filter-mapping>
+ <context-param>
+ <param-name>argeo.security.systemKey</param-name>
+ <param-value>argeo</param-value>
+ </context-param>
</web-app>
public interface ArgeoSecurityService {
public void newUser(ArgeoUser argeoUser);
-
+
public void updateUser(ArgeoUser user);
public void updateUserPassword(String username, String password);
public void newRole(String role);
public ArgeoSecurityDao getSecurityDao();
+
+ public Runnable wrapWithSystemAuthentication(final Runnable runnable);
}
import org.argeo.security.ArgeoSecurityService;
import org.argeo.security.ArgeoUser;
import org.argeo.security.SimpleArgeoUser;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.security.Authentication;
+import org.springframework.security.AuthenticationManager;
+import org.springframework.security.context.SecurityContext;
+import org.springframework.security.context.SecurityContextHolder;
public class DefaultSecurityService implements ArgeoSecurityService {
private ArgeoSecurity argeoSecurity = new DefaultArgeoSecurity();
private ArgeoSecurityDao securityDao;
+ private AuthenticationManager authenticationManager;
+
+ private String systemAuthenticationKey;
public ArgeoSecurityDao getSecurityDao() {
return securityDao;
securityDao.update(simpleArgeoUser);
}
+ public TaskExecutor createSystemAuthenticatedTaskExecutor() {
+ return new SimpleAsyncTaskExecutor() {
+ private static final long serialVersionUID = -8126773862193265020L;
+
+ @Override
+ public Thread createThread(Runnable runnable) {
+ return super
+ .createThread(wrapWithSystemAuthentication(runnable));
+ }
+
+ };
+ }
+
+ /**
+ * Wraps another runnable, adding security context <br/>
+ * TODO: secure the call to this method with Java Security
+ */
+ public Runnable wrapWithSystemAuthentication(final Runnable runnable) {
+ return new Runnable() {
+
+ public void run() {
+ SecurityContext securityContext = SecurityContextHolder
+ .getContext();
+ Authentication auth = authenticationManager
+ .authenticate(new InternalAuthentication(
+ systemAuthenticationKey));
+ securityContext.setAuthentication(auth);
+
+ runnable.run();
+ }
+ };
+ }
+
public void setArgeoSecurity(ArgeoSecurity argeoSecurity) {
this.argeoSecurity = argeoSecurity;
}
this.securityDao = dao;
}
+ public void setAuthenticationManager(
+ AuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
+ }
+
+ public void setSystemAuthenticationKey(String systemAuthenticationKey) {
+ this.systemAuthenticationKey = systemAuthenticationKey;
+ }
+
}
--- /dev/null
+package org.argeo.security.core;
+
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.security.adapters.PrincipalSpringSecurityUserToken;
+
+public class InternalAuthentication extends PrincipalSpringSecurityUserToken {
+ private static final long serialVersionUID = -6783376375615949315L;
+ private final static String SYSTEM_USERNAME = "system";
+ private final static String SYSTEM_ROLE = "ROLE_SYSTEM";
+
+ public InternalAuthentication(String key) {
+ super(
+ key,
+ SYSTEM_USERNAME,
+ key,
+ new GrantedAuthority[] { new GrantedAuthorityImpl(SYSTEM_ROLE) },
+ SYSTEM_USERNAME);
+ }
+
+}
--- /dev/null
+package org.argeo.security.core;
+
+import org.argeo.security.ArgeoSecurityService;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+
+public class SystemAuthenticatedTaskExecutor extends SimpleAsyncTaskExecutor {
+ private static final long serialVersionUID = 453384889461147359L;
+
+ private ArgeoSecurityService securityService;
+
+ @Override
+ public Thread createThread(Runnable runnable) {
+ return super.createThread(securityService
+ .wrapWithSystemAuthentication(runnable));
+ }
+
+ public void setSecurityService(ArgeoSecurityService securityService) {
+ this.securityService = securityService;
+ }
+
+}
public void setGroupClasses(String[] groupClasses) {
this.groupClasses = groupClasses;
}
+
+ public UserDetailsManager getUserDetailsManager() {
+ return userDetailsManager;
+ }
+
}
--- /dev/null
+additional.bundles = org.springframework.beans
+source.. = src/main/java/
--- /dev/null
+package org.argeo.security.mvc;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.ui.rememberme.TokenBasedRememberMeServices;
+
+public class ArgeoRememberMeServices extends TokenBasedRememberMeServices {
+ public final static String DEFAULT_COOKIE_NAME = "ARGEO_SECURITY";
+
+ public ArgeoRememberMeServices() {
+ setCookieName(DEFAULT_COOKIE_NAME);
+ }
+
+ /**
+ * Sets a "cancel cookie" (with maxAge = 0) on the response to disable
+ * persistent logins.
+ *
+ * @param request
+ * @param response
+ */
+ protected void cancelCookie(HttpServletRequest request,
+ HttpServletResponse response) {
+ Cookie cookie = new Cookie(getCookieName(), null);
+ cookie.setMaxAge(0);
+ cookie.setPath("/");
+
+ response.addCookie(cookie);
+ }
+
+ /**
+ * Sets the cookie on the response
+ *
+ * @param tokens
+ * the tokens which will be encoded to make the cookie value.
+ * @param maxAge
+ * the value passed to {@link Cookie#setMaxAge(int)}
+ * @param request
+ * the request
+ * @param response
+ * the response to add the cookie to.
+ */
+ protected void setCookie(String[] tokens, int maxAge,
+ HttpServletRequest request, HttpServletResponse response) {
+ String cookieValue = encodeCookie(tokens);
+ Cookie cookie = new Cookie(getCookieName(), cookieValue);
+ cookie.setMaxAge(maxAge);
+ cookie.setPath("/");
+ response.addCookie(cookie);
+ }
+
+}
org.springframework.security;resolution:=optional,
org.springframework.security.context;resolution:=optional,
org.springframework.security.providers;resolution:=optional,
+ org.springframework.security.providers.rememberme;resolution:=optional,
org.springframework.security.ui;resolution:=optional,
org.springframework.security.ui.savedrequest;resolution:=optional,
org.springframework.security.userdetails;resolution:=optional,
<version>${version.maven-bundle-plugin}</version>
<configuration>
<instructions>
+ <Fragment-Host>org.argeo.dep.osgi.jackrabbit</Fragment-Host>
<Export-Package>
org.argeo.jcr.*,
org.argeo.server.jackrabbit.*,
</Export-Package>
<Import-Package>
*,
+ org.springframework.security.providers.jaas;resolution:="optional",
junit.framework;resolution:="optional"
</Import-Package>
</instructions>
<artifactId>org.springframework.web.servlet</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.springframework.security</groupId>
+ <artifactId>org.springframework.security</artifactId>
+ </dependency>
+
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
--- /dev/null
+package org.argeo.jcr;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.ArgeoException;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+
+public class ThreadBoundJcrSessionFactory implements FactoryBean,
+ DisposableBean {
+ private final static Log log = LogFactory
+ .getLog(ThreadBoundJcrSessionFactory.class);
+
+ private Repository repository;
+ private List<Session> activeSessions = Collections
+ .synchronizedList(new ArrayList<Session>());
+
+ private ThreadLocal<Session> session = new ThreadLocal<Session>();
+ private boolean destroying = false;
+ private final Session proxiedSession;
+
+ public ThreadBoundJcrSessionFactory() {
+ Class<?>[] interfaces = { Session.class };
+ proxiedSession = (Session) Proxy.newProxyInstance(getClass()
+ .getClassLoader(), interfaces, new InvocationHandler() {
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ Session threadSession = session.get();
+ if (threadSession == null) {
+ if ("logout".equals(method.getName()))// no need to login
+ return Void.TYPE;
+ threadSession = login();
+ session.set(threadSession);
+ }
+
+ Object ret = method.invoke(threadSession, args);
+ if ("logout".equals(method.getName())) {
+ session.remove();
+ if (!destroying)
+ activeSessions.remove(threadSession);
+ if (log.isTraceEnabled())
+ log.trace("Logged out from JCR session "
+ + threadSession + "; userId="
+ + threadSession.getUserID());
+ }
+ return ret;
+ }
+ });
+ }
+
+ protected Session login() {
+ try {
+ Session sess = repository.login();
+ if (log.isTraceEnabled())
+ log.trace("Log in to JCR session " + sess + "; userId="
+ + sess.getUserID());
+ // Thread.dumpStack();
+ activeSessions.add(sess);
+ return sess;
+ } catch (RepositoryException e) {
+ throw new ArgeoException("Cannot log in to repository", e);
+ }
+ }
+
+ public Object getObject() {
+ return proxiedSession;
+ }
+
+ public void destroy() throws Exception {
+ if (log.isDebugEnabled())
+ log.debug("Cleaning up " + activeSessions.size()
+ + " active JCR sessions...");
+
+ destroying = true;
+ for (Session sess : activeSessions) {
+ sess.logout();
+ }
+ activeSessions.clear();
+ }
+
+ public Class<? extends Session> getObjectType() {
+ return Session.class;
+ }
+
+ public boolean isSingleton() {
+ return true;
+ }
+
+ public void setRepository(Repository repository) {
+ this.repository = repository;
+ }
+
+}
--- /dev/null
+package org.argeo.server.jcr.mvc;
+
+import javax.jcr.Session;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.context.request.WebRequestInterceptor;
+
+public class OpenSessionInViewJcrInterceptor implements WebRequestInterceptor {
+ private final static Log log = LogFactory
+ .getLog(OpenSessionInViewJcrInterceptor.class);
+
+ private Session session;
+
+ public void preHandle(WebRequest request) throws Exception {
+ if (log.isTraceEnabled())
+ log.trace("preHandle: " + request);
+ // Authentication auth = SecurityContextHolder.getContext()
+ // .getAuthentication();
+ // if (auth != null)
+ // log.debug("auth=" + auth + ", authenticated="
+ // + auth.isAuthenticated() + ", name=" + auth.getName());
+ // else
+ // log.debug("No auth");
+
+ // FIXME: find a safer way to initialize
+ // FIXME: not really needed to initialize here
+ //session.getRepository();
+ }
+
+ public void postHandle(WebRequest request, ModelMap model) throws Exception {
+ // if (log.isDebugEnabled())
+ // log.debug("postHandle: " + request);
+ }
+
+ public void afterCompletion(WebRequest request, Exception ex)
+ throws Exception {
+ if (log.isTraceEnabled())
+ log.trace("afterCompletion: " + request);
+ // FIXME: only close session that were open
+ session.logout();
+ }
+
+ public void setSession(Session session) {
+ this.session = session;
+ }
+
+}