From 86140b8db15a11cfd942892eface6a4f90329a41 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Wed, 30 Sep 2015 14:57:31 +0000 Subject: [PATCH] Remove dependency to Spring Security git-svn-id: https://svn.argeo.org/commons/trunk@8458 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- org.argeo.cms/bnd.bnd | 11 +- .../internal/auth/AbstractLoginModule.java | 205 ------ .../internal/auth/AnonymousLoginModule.java | 70 -- .../cms/internal/auth/EndUserLoginModule.java | 108 --- .../auth/GrantedAuthorityPrincipal.java | 64 -- .../auth/OsJcrAuthenticationProvider.java | 119 ---- .../auth/RemoteJcrAuthenticationProvider.java | 143 ---- .../internal/auth/SingleUserLoginModule.java | 36 - .../cms/internal/auth/SystemLoginModule.java | 38 -- .../argeo/cms/internal/kernel/Activator.java | 4 +- .../org/argeo/cms/internal/kernel/Kernel.java | 5 - .../cms/internal/kernel/NodeSecurity.java | 22 +- .../internal/useradmin/AbstractJcrUser.java | 29 - .../internal/useradmin/JcrAuthorization.java | 39 -- .../cms/internal/useradmin/JcrEndUser.java | 33 - .../cms/internal/useradmin/JcrGroup.java | 60 -- .../argeo/cms/internal/useradmin/JcrRole.java | 29 - .../internal/useradmin/JcrRoleProperties.java | 73 -- .../cms/internal/useradmin/JcrUserAdmin.java | 145 ---- .../useradmin/OsJcrUserAdminService.java | 155 ----- .../useradmin/SimpleJcrSecurityModel.java | 183 ----- .../jackrabbit/JackrabbitSecurityModel.java | 109 --- .../JackrabbitUserAdminService.java | 473 ------------- .../jackrabbit/ScopedSessionProvider.java | 171 ----- .../ldap/ArgeoLdapShaPasswordEncoder.java | 36 - .../ldap/ArgeoLdapUserDetailsManager.java | 146 ---- .../useradmin/ldap/ArgeoUserAdminDaoLdap.java | 195 ------ .../useradmin/ldap/JcrLdapSynchronizer.java | 623 ------------------ .../ldap/JcrUserDetailsContextMapper.java | 98 --- org.argeo.security.core/bnd.bnd | 2 +- org.argeo.security.core/build.properties | 3 +- .../org/argeo/security/PasswordSandbox.java | 58 -- .../security/NodeAuthenticationToken.java | 69 -- .../argeo/security/OsAuthenticationToken.java | 187 ------ .../src/org/argeo/security/SecurityUtils.java | 91 +-- .../argeo/security/SystemAuthentication.java | 26 - .../security/SystemExecutionService.java | 42 -- .../org/argeo/security/UserAdminService.java | 60 -- .../core/AbstractSystemExecution.java | 56 -- .../core/AsyncSystemTaskExecutor.java | 55 -- ...catedApplicationContextInitialization.java | 66 +- .../core/AuthenticationProvidersRegister.java | 64 -- .../security/core/InternalAuthentication.java | 40 -- .../core/InternalAuthenticationProvider.java | 35 - .../core/KeyBasedSystemExecutionService.java | 64 -- .../core/MatchingAuthenticationProvider.java | 87 --- .../core/OsAuthenticationProvider.java | 62 -- .../argeo/security/jcr/JcrUserDetails.java | 154 ----- .../argeo/security/jcr/NewUserDetails.java | 41 -- .../jcr/RemoteJcrRepositoryWrapper.java | 145 ---- .../jcr/SecureThreadBoundSession.java | 56 -- .../security/jackrabbit/ArgeoLoginModule.java | 147 ----- org.argeo.security.ui.admin/bnd.bnd | 2 - .../ui/admin/internal/commands/NewUser.java | 11 +- .../internal/parts/UserBatchUpdateWizard.java | 604 ----------------- .../admin/internal/parts/UserRolesPage.java | 231 ------- .../security/ui/rap/SecureEntryPoint.java | 29 +- .../org/argeo/security/ui/PrivilegedJob.java | 17 +- .../security/ui/internal/CurrentUser.java | 64 +- pom.xml | 33 +- 60 files changed, 101 insertions(+), 5922 deletions(-) delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/auth/AbstractLoginModule.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/auth/AnonymousLoginModule.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/auth/EndUserLoginModule.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/auth/GrantedAuthorityPrincipal.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/auth/OsJcrAuthenticationProvider.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/auth/RemoteJcrAuthenticationProvider.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/auth/SingleUserLoginModule.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/auth/SystemLoginModule.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/AbstractJcrUser.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrAuthorization.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrEndUser.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrGroup.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrRole.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrRoleProperties.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrUserAdmin.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/OsJcrUserAdminService.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/SimpleJcrSecurityModel.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitSecurityModel.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitUserAdminService.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/ScopedSessionProvider.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoLdapShaPasswordEncoder.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoLdapUserDetailsManager.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoUserAdminDaoLdap.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/JcrLdapSynchronizer.java delete mode 100644 org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/JcrUserDetailsContextMapper.java delete mode 100644 org.argeo.security.core/ext/test/org/argeo/security/PasswordSandbox.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/NodeAuthenticationToken.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/OsAuthenticationToken.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/SystemAuthentication.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/SystemExecutionService.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/UserAdminService.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/core/AsyncSystemTaskExecutor.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/core/AuthenticationProvidersRegister.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/core/InternalAuthentication.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/core/InternalAuthenticationProvider.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/core/KeyBasedSystemExecutionService.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/core/MatchingAuthenticationProvider.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/core/OsAuthenticationProvider.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/jcr/JcrUserDetails.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/jcr/NewUserDetails.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/jcr/RemoteJcrRepositoryWrapper.java delete mode 100644 org.argeo.security.core/src/org/argeo/security/jcr/SecureThreadBoundSession.java delete mode 100644 org.argeo.security.jackrabbit/src/org/argeo/security/jackrabbit/ArgeoLoginModule.java delete mode 100644 org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java delete mode 100644 org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserRolesPage.java diff --git a/org.argeo.cms/bnd.bnd b/org.argeo.cms/bnd.bnd index 6eecc6b85..e98fea919 100644 --- a/org.argeo.cms/bnd.bnd +++ b/org.argeo.cms/bnd.bnd @@ -1,12 +1,8 @@ Bundle-SymbolicName: org.argeo.cms;singleton=true Bundle-Activator: org.argeo.cms.internal.kernel.Activator -Import-Package: org.springframework.core,\ -org.springframework.dao,\ -javax.jcr.security,\ +Import-Package: javax.jcr.security,\ org.xml.sax,\ org.argeo.jcr,\ -org.springframework.context,\ -org.springframework.security.authentication.jaas,\ org.apache.jackrabbit.api,\ org.apache.jackrabbit.commons,\ org.apache.jackrabbit.core.security.user,\ @@ -19,8 +15,7 @@ org.h2;resolution:=optional,\ org.postgresql;resolution:=optional,\ org.apache.commons.vfs2.*;resolution:=optional,\ org.apache.jackrabbit.*;resolution:=optional,\ -org.springframework.ldap.*;resolution:=optional,\ -org.springframework.security.ldap.*;resolution:=optional,\ -org.springframework.security.provisioning;resolution:=optional,\ org.joda.time.*;resolution:=optional,\ +org.springframework.context,\ +org.springframework.core.io,\ * diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/AbstractLoginModule.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/AbstractLoginModule.java deleted file mode 100644 index 89312a3dc..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/AbstractLoginModule.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.auth; - -import java.io.IOException; -import java.util.Map; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.cms.internal.kernel.Activator; -import org.eclipse.rap.rwt.RWT; -import org.eclipse.swt.widgets.Display; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; - -/** Login module which caches one subject per thread. */ -public abstract class AbstractLoginModule implements LoginModule { - /** - * From org.springframework.security.context. - * HttpSessionContextIntegrationFilter - */ - private final static String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT"; - - private final static Log log = LogFactory.getLog(AbstractLoginModule.class); - private CallbackHandler callbackHandler; - private Subject subject; - - private Authentication authentication; - - // state - private BundleContext bundleContext; - private ServiceReference authenticationManager; - - protected abstract Authentication processLogin( - CallbackHandler callbackHandler) throws LoginException, - UnsupportedCallbackException, IOException, InterruptedException; - - @Override - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) { - this.callbackHandler = callbackHandler; - this.subject = subject; - this.bundleContext = Activator.getBundleContext(); - this.authenticationManager = bundleContext - .getServiceReference(AuthenticationManager.class); - } - - @Override - public boolean login() throws LoginException { - try { - Authentication currentAuth = SecurityContextHolder.getContext() - .getAuthentication(); - - if (currentAuth == null) { - // Pre-auth - // TODO Do it at Spring Security level? - try { - // try to load authentication from session - HttpServletRequest httpRequest = RWT.getRequest(); - HttpSession httpSession = httpRequest.getSession(); - // log.debug(httpSession.getId()); - Object contextFromSessionObject = httpSession - .getAttribute(SPRING_SECURITY_CONTEXT_KEY); - if (contextFromSessionObject != null) { - currentAuth = (Authentication) contextFromSessionObject; - SecurityContextHolder.getContext().setAuthentication( - currentAuth); - } - } catch (Exception e) { - if (log.isTraceEnabled()) - log.trace("Could not get session", e); - // silent - } - } - - // thread already logged in - if (currentAuth != null) { - if (subject.getPrincipals(Authentication.class).size() == 0) { - // throw new LoginException( - // "Security context set but not Authentication principal"); - } else { - Authentication principal = subject - .getPrincipals(Authentication.class).iterator() - .next(); - if (principal != currentAuth) - throw new LoginException( - "Already authenticated with a different auth"); - } - return true; - } - - // if (callbackHandler == null) - // throw new LoginException("No callback handler available"); - - authentication = processLogin(callbackHandler); - if (authentication != null) { - // - // SET THE AUTHENTICATION - // - SecurityContext securityContext = SecurityContextHolder - .getContext(); - securityContext.setAuthentication(authentication); - try { - HttpServletRequest httpRequest = RWT.getRequest(); - HttpSession httpSession = httpRequest.getSession(); - if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) == null) - httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, - authentication); - } catch (Exception e) { - if (log.isTraceEnabled()) - log.trace("Could not add security context to session", - e); - } - return true; - } else { - throw new LoginException("No authentication returned"); - } - } catch (LoginException e) { - throw e; - } catch (ThreadDeath e) { - LoginException le = new LoginException( - "Spring Security login thread died"); - le.initCause(e); - throw le; - } catch (Exception e) { - LoginException le = new LoginException( - "Spring Security login failed"); - le.initCause(e); - throw le; - } - } - - @Override - public boolean logout() throws LoginException { - SecurityContextHolder.getContext().setAuthentication(null); - if (Display.getCurrent() != null) { - HttpServletRequest httpRequest = RWT.getRequest(); - if (httpRequest != null) { - HttpSession httpSession = httpRequest.getSession(); - if (httpSession.getAttribute(SPRING_SECURITY_CONTEXT_KEY) != null) - httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, null); - // expire session - httpSession.setMaxInactiveInterval(0); - } - } - return true; - } - - @Override - public boolean commit() throws LoginException { - return true; - } - - @Override - public boolean abort() throws LoginException { - SecurityContextHolder.getContext().setAuthentication(null); - return true; - } - - /** - * Return the related {@link BundleContext} (never null), or throws an - * Exception if the login module was not properly initialised. - */ - protected BundleContext getBundleContext() { - if (bundleContext == null) - throw new ArgeoException("No bundle context provided"); - return bundleContext; - } - - AuthenticationManager getAuthenticationManager() { - BundleContext bc = getBundleContext(); - assert authenticationManager != null; - return bc.getService(authenticationManager); - } - - protected Subject getSubject() { - return subject; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/AnonymousLoginModule.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/AnonymousLoginModule.java deleted file mode 100644 index 855524961..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/AnonymousLoginModule.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.auth; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginException; - -import org.argeo.cms.KernelHeader; -import org.argeo.cms.internal.kernel.Activator; -import org.argeo.util.LocaleCallback; -import org.argeo.util.LocaleUtils; -import org.springframework.security.authentication.AnonymousAuthenticationToken; -import org.springframework.security.core.Authentication; - -/** Login module which caches one subject per thread. */ -public class AnonymousLoginModule extends AbstractLoginModule { - /** Comma separated list of locales */ - private String availableLocales = null; - - @Override - protected Authentication processLogin(CallbackHandler callbackHandler) - throws LoginException, UnsupportedCallbackException, IOException, - InterruptedException { - Locale selectedLocale = null; - // multi locale - if (callbackHandler != null) - if (availableLocales != null && !availableLocales.trim().equals("")) { - LocaleCallback localeCallback = new LocaleCallback( - availableLocales); - callbackHandler.handle(new Callback[] { localeCallback }); - selectedLocale = localeCallback.getSelectedLocale(); - } else { - callbackHandler.handle(new Callback[] {}); - } - - List authorities = Collections - .singletonList(new GrantedAuthorityPrincipal( - KernelHeader.ROLE_ANONYMOUS)); - AnonymousAuthenticationToken anonymousToken = new AnonymousAuthenticationToken( - Activator.getSystemKey(), KernelHeader.USERNAME_ANONYMOUS, - authorities); - - Authentication auth = getAuthenticationManager().authenticate( - anonymousToken); - - if (selectedLocale != null) - LocaleUtils.threadLocale.set(selectedLocale); - return auth; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/EndUserLoginModule.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/EndUserLoginModule.java deleted file mode 100644 index 128dd7a36..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/EndUserLoginModule.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.auth; - -import java.io.IOException; -import java.util.Locale; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.CredentialNotFoundException; -import javax.security.auth.login.LoginException; - -import org.argeo.security.NodeAuthenticationToken; -import org.argeo.util.LocaleCallback; -import org.argeo.util.LocaleUtils; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.core.Authentication; - -/** Authenticates an end user */ -public class EndUserLoginModule extends AbstractLoginModule { - final static String NODE_REPO_URI = "argeo.node.repo.uri"; - - private Long waitBetweenFailedLoginAttempts = 5 * 1000l; - - private Boolean remote = false; - /** Comma separated list of locales */ - private String availableLocales = ""; - - @Override - protected Authentication processLogin(CallbackHandler callbackHandler) - throws LoginException, UnsupportedCallbackException, IOException, - InterruptedException { - if (callbackHandler == null) - return null; - - // ask for username and password - NameCallback nameCallback = new NameCallback("User"); - PasswordCallback passwordCallback = new PasswordCallback("Password", - false); - final String defaultNodeUrl = System.getProperty(NODE_REPO_URI, - "http://localhost:7070/org.argeo.jcr.webapp/remoting/node"); - NameCallback urlCallback = new NameCallback("Site URL", defaultNodeUrl); - LocaleCallback localeCallback = new LocaleCallback(availableLocales); - // handle callbacks - if (remote) - callbackHandler.handle(new Callback[] { nameCallback, - passwordCallback, urlCallback, localeCallback }); - else - callbackHandler.handle(new Callback[] { nameCallback, - passwordCallback, localeCallback }); - - Locale selectedLocale = localeCallback.getSelectedLocale(); - - // create credentials - final String username = nameCallback.getName(); - if (username == null || username.trim().equals("")) - throw new CredentialNotFoundException("No credentials provided"); - - char[] password = {}; - if (passwordCallback.getPassword() != null) - password = passwordCallback.getPassword(); - else - throw new CredentialNotFoundException("No credentials provided"); - - NodeAuthenticationToken credentials; - if (remote) { - String url = urlCallback.getName(); - credentials = new NodeAuthenticationToken(username, password, url); - } else { - credentials = new NodeAuthenticationToken(username, password); - } - - Authentication auth; - try { - auth = getAuthenticationManager().authenticate(credentials); - } catch (BadCredentialsException e) { - // wait between failed login attempts - Thread.sleep(waitBetweenFailedLoginAttempts); - throw e; - } - - if (selectedLocale != null) - LocaleUtils.threadLocale.set(selectedLocale); - - return auth; - } - - @Override - public boolean commit() throws LoginException { - return super.commit(); - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/GrantedAuthorityPrincipal.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/GrantedAuthorityPrincipal.java deleted file mode 100644 index a0622da3b..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/GrantedAuthorityPrincipal.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.auth; - -import java.security.Principal; - -import javax.security.auth.Subject; - -import org.springframework.security.core.GrantedAuthority; - -/** - * A {@link Principal} which is also a {@link GrantedAuthority}, so that the - * Spring Security can be used to quickly populate a {@link Subject} principals. - */ -public final class GrantedAuthorityPrincipal implements Principal, - GrantedAuthority { - private static final long serialVersionUID = 6768044196343543328L; - private final String authority; - - public GrantedAuthorityPrincipal(String authority) { - this.authority = authority; - } - - @Override - public String getAuthority() { - return authority; - } - - @Override - public String getName() { - return authority; - } - - @Override - public int hashCode() { - return getName().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof GrantedAuthorityPrincipal)) - return false; - return getName().equals(((GrantedAuthorityPrincipal) obj).getName()); - } - - @Override - public String toString() { - return "Granted Authority " + getName(); - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/OsJcrAuthenticationProvider.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/OsJcrAuthenticationProvider.java deleted file mode 100644 index a394baf1e..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/OsJcrAuthenticationProvider.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.auth; - -import java.util.Collection; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.cms.internal.useradmin.SimpleJcrSecurityModel; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.OsAuthenticationToken; -import org.argeo.security.SecurityUtils; -import org.argeo.security.core.OsAuthenticationProvider; -import org.argeo.security.jcr.JcrUserDetails; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -/** Relies on OS to authenticate and additionally setup JCR */ -public class OsJcrAuthenticationProvider extends OsAuthenticationProvider { - private Repository repository; - private Session nodeSession; - - private UserDetails userDetails; - private JcrSecurityModel jcrSecurityModel = new SimpleJcrSecurityModel(); - - private final static String JVM_OSUSER = System.getProperty("user.name"); - - public void init() { - try { - nodeSession = repository.login(); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot initialize", e); - } - } - - public void destroy() { - JcrUtils.logoutQuietly(nodeSession); - } - - public Authentication authenticate(Authentication authentication) - throws AuthenticationException { - if (authentication instanceof UsernamePasswordAuthenticationToken) { - // deal with remote access to internal server - // FIXME very primitive and unsecure at this sSession adminSession - // =tage - // consider using the keyring for username / password authentication - // or certificate - UsernamePasswordAuthenticationToken upat = (UsernamePasswordAuthenticationToken) authentication; - if (!upat.getPrincipal().toString().equals(JVM_OSUSER)) - throw new BadCredentialsException("Wrong credentials"); - UsernamePasswordAuthenticationToken authen = new UsernamePasswordAuthenticationToken( - authentication.getPrincipal(), - authentication.getCredentials(), getBaseAuthorities()); - authen.setDetails(userDetails); - return authen; - } else if (authentication instanceof OsAuthenticationToken) { - OsAuthenticationToken authen = (OsAuthenticationToken) super - .authenticate(authentication); - try { - // WARNING: at this stage we assume that the java properties - // will have the same value - Collection authorities = getBaseAuthorities(); - String username = JVM_OSUSER; - Node userProfile = jcrSecurityModel.sync(nodeSession, username, - SecurityUtils.authoritiesToStringList(authorities)); - JcrUserDetails.checkAccountStatus(userProfile); - - userDetails = new JcrUserDetails(userProfile, authen - .getCredentials().toString(), authorities); - authen.setDetails(userDetails); - return authen; - } catch (RepositoryException e) { - JcrUtils.discardQuietly(nodeSession); - throw new ArgeoException( - "Unexpected exception when synchronizing OS and JCR security ", - e); - } - } else { - throw new ArgeoException("Unsupported authentication " - + authentication.getClass()); - } - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - - public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { - this.jcrSecurityModel = jcrSecurityModel; - } - - @SuppressWarnings("rawtypes") - public boolean supports(Class authentication) { - return OsAuthenticationToken.class.isAssignableFrom(authentication) - || UsernamePasswordAuthenticationToken.class - .isAssignableFrom(authentication); - } -} \ No newline at end of file diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/RemoteJcrAuthenticationProvider.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/RemoteJcrAuthenticationProvider.java deleted file mode 100644 index b9ebaf761..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/RemoteJcrAuthenticationProvider.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.auth; - -import java.util.ArrayList; -import java.util.Dictionary; -import java.util.Hashtable; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.RepositoryFactory; -import javax.jcr.Session; -import javax.jcr.SimpleCredentials; -import javax.jcr.Value; - -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.security.NodeAuthenticationToken; -import org.argeo.security.jcr.JcrUserDetails; -import org.argeo.security.jcr.RemoteJcrRepositoryWrapper; -import org.osgi.framework.BundleContext; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - -/** Connects to a JCR repository and delegates authentication to it. */ -public class RemoteJcrAuthenticationProvider implements AuthenticationProvider, - ArgeoNames { - private RepositoryFactory repositoryFactory; - private BundleContext bundleContext; - - public final static String ROLE_REMOTE = "ROLE_REMOTE"; - - public Authentication authenticate(Authentication authentication) - throws AuthenticationException { - NodeAuthenticationToken siteAuth = (NodeAuthenticationToken) authentication; - String url = siteAuth.getUrl(); - if (url == null)// TODO? login on own node - throw new ArgeoException("No url set in " + siteAuth); - Session session; - - Node userProfile; - try { - SimpleCredentials sp = new SimpleCredentials(siteAuth.getName(), - siteAuth.getCredentials().toString().toCharArray()); - // get repository - Repository repository = new RemoteJcrRepositoryWrapper( - repositoryFactory, url, sp); - if (bundleContext != null) { - Dictionary serviceProperties = new Hashtable(); - serviceProperties.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, - ArgeoJcrConstants.ALIAS_NODE); - serviceProperties - .put(ArgeoJcrConstants.JCR_REPOSITORY_URI, url); - bundleContext.registerService(Repository.class.getName(), - repository, serviceProperties); - } - // Repository repository = ArgeoJcrUtils.getRepositoryByUri( - // repositoryFactory, url); - // if (repository == null) - // throw new ArgeoException("Cannot connect to " + url); - - session = repository.login(sp, null); - - userProfile = UserJcrUtils.getUserProfile(session, sp.getUserID()); - JcrUserDetails.checkAccountStatus(userProfile); - - // Node userHome = UserJcrUtils.getUserHome(session); - // if (userHome == null || - // !userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) - // throw new ArgeoException("No profile for user " - // + siteAuth.getName() + " in security workspace " - // + siteAuth.getSecurityWorkspace() + " of " - // + siteAuth.getUrl()); - // userProfile = userHome.getNode(ArgeoNames.ARGEO_PROFILE); - } catch (RepositoryException e) { - throw new BadCredentialsException( - "Cannot authenticate " + siteAuth, e); - } - - try { - // Node userHome = UserJcrUtils.getUserHome(session); - // retrieve remote roles - List authoritiesList = new ArrayList(); - if (userProfile != null - && userProfile.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) { - Value[] roles = userProfile.getProperty( - ArgeoNames.ARGEO_REMOTE_ROLES).getValues(); - for (int i = 0; i < roles.length; i++) - authoritiesList.add(new SimpleGrantedAuthority(roles[i] - .getString())); - } - authoritiesList.add(new SimpleGrantedAuthority(ROLE_REMOTE)); - - // create authenticated objects - // GrantedAuthority[] authorities = authoritiesList - // .toArray(new GrantedAuthority[authoritiesList.size()]); - JcrUserDetails userDetails = new JcrUserDetails(userProfile, - siteAuth.getCredentials().toString(), authoritiesList); - NodeAuthenticationToken authenticated = new NodeAuthenticationToken( - siteAuth, authoritiesList); - authenticated.setDetails(userDetails); - return authenticated; - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected exception when authenticating to " + url, e); - } - } - - @SuppressWarnings("rawtypes") - public boolean supports(Class authentication) { - return NodeAuthenticationToken.class.isAssignableFrom(authentication); - } - - public void setRepositoryFactory(RepositoryFactory repositoryFactory) { - this.repositoryFactory = repositoryFactory; - } - - public void setBundleContext(BundleContext bundleContext) { - this.bundleContext = bundleContext; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/SingleUserLoginModule.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/SingleUserLoginModule.java deleted file mode 100644 index a00c9220d..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/SingleUserLoginModule.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.auth; - -import java.io.IOException; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginException; - -import org.argeo.security.OsAuthenticationToken; -import org.springframework.security.core.Authentication; - -/** Login module which caches one subject per thread. */ -public class SingleUserLoginModule extends AbstractLoginModule { - @Override - protected Authentication processLogin(CallbackHandler callbackHandler) - throws LoginException, UnsupportedCallbackException, IOException, - InterruptedException { - OsAuthenticationToken token = new OsAuthenticationToken(); - return getAuthenticationManager().authenticate(token); - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/auth/SystemLoginModule.java b/org.argeo.cms/src/org/argeo/cms/internal/auth/SystemLoginModule.java deleted file mode 100644 index 5e8587d25..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/auth/SystemLoginModule.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.auth; - -import java.io.IOException; - -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginException; - -import org.argeo.cms.internal.kernel.Activator; -import org.argeo.security.core.InternalAuthentication; -import org.springframework.security.core.Authentication; - -/** Login module which caches one subject per thread. */ -public class SystemLoginModule extends AbstractLoginModule { - @Override - protected Authentication processLogin(CallbackHandler callbackHandler) - throws LoginException, UnsupportedCallbackException, IOException, - InterruptedException { - InternalAuthentication token = new InternalAuthentication( - Activator.getSystemKey()); - return getAuthenticationManager().authenticate(token); - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java index 1b21f5663..a942b4b18 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Activator.java @@ -4,7 +4,6 @@ import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.argeo.security.SystemAuthentication; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; @@ -13,12 +12,13 @@ import org.osgi.framework.BundleContext; * access to kernel information for the rest of the bundle (and only it) */ public class Activator implements BundleActivator { + public final static String SYSTEM_KEY_PROPERTY = "argeo.security.systemKey"; private final Log log = LogFactory.getLog(Activator.class); private final static String systemKey; static { systemKey = UUID.randomUUID().toString(); - System.setProperty(SystemAuthentication.SYSTEM_KEY_PROPERTY, systemKey); + System.setProperty(SYSTEM_KEY_PROPERTY, systemKey); } private static BundleContext bundleContext; diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java index 08dad56b8..703bf764d 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/Kernel.java @@ -20,14 +20,12 @@ import org.argeo.cms.CmsException; import org.argeo.cms.internal.transaction.SimpleTransactionManager; import org.argeo.jackrabbit.OsgiJackrabbitRepositoryFactory; import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.security.core.InternalAuthentication; import org.eclipse.equinox.http.servlet.ExtendedHttpService; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceListener; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; -import org.springframework.security.core.context.SecurityContextHolder; /** * Argeo CMS Kernel. Responsible for : @@ -77,9 +75,6 @@ final class Kernel implements ServiceListener { Thread.currentThread().setContextClassLoader( Kernel.class.getClassLoader()); long begin = System.currentTimeMillis(); - InternalAuthentication initAuth = new InternalAuthentication( - KernelConstants.DEFAULT_SECURITY_KEY); - SecurityContextHolder.getContext().setAuthentication(initAuth); try { // Transaction diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java index 0b6ce9a85..910953e30 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeSecurity.java @@ -29,12 +29,9 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.osgi.service.useradmin.UserAdmin; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; /** Authentication and user management. */ -class NodeSecurity implements AuthenticationManager { +class NodeSecurity { private final static Log log; static { log = LogFactory.getLog(NodeSecurity.class); @@ -54,8 +51,6 @@ class NodeSecurity implements AuthenticationManager { private final NodeUserAdmin userAdmin; private final Subject kernelSubject; - private ServiceRegistration authenticationManagerReg; - private ServiceRegistration userAdminReg; public NodeSecurity(BundleContext bundleContext) { @@ -103,14 +98,9 @@ class NodeSecurity implements AuthenticationManager { public void publish() { userAdminReg = bundleContext.registerService(UserAdmin.class, userAdmin, userAdmin.currentState()); - // dummy auth manager, in order to smooth transition from Argeo 1 - authenticationManagerReg = bundleContext.registerService( - AuthenticationManager.class, this, null); - } + } void destroy() { - authenticationManagerReg.unregister(); - userAdmin.destroy(); userAdminReg.unregister(); @@ -134,14 +124,6 @@ class NodeSecurity implements AuthenticationManager { return kernelSubject; } - @Override - public Authentication authenticate(Authentication authentication) - throws AuthenticationException { - log.error("Authentication manager is deprecated and should not be used."); - throw new ProviderNotFoundException( - "Authentication manager is deprecated and should not be used."); - } - private void createKeyStoreIfNeeded() { char[] ksPwd = "changeit".toCharArray(); char[] keyPwd = Arrays.copyOf(ksPwd, ksPwd.length); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/AbstractJcrUser.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/AbstractJcrUser.java deleted file mode 100644 index 7d63b8693..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/AbstractJcrUser.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.argeo.cms.internal.useradmin; - -import java.util.Dictionary; - -import org.argeo.cms.CmsException; -import org.osgi.service.useradmin.Role; -import org.osgi.service.useradmin.User; - -abstract class AbstractJcrUser extends JcrRole implements User { - public AbstractJcrUser(String name) { - super(name); - } - - @Override - public int getType() { - return Role.USER; - } - - @Override - public Dictionary getCredentials() { - throw new CmsException("Not implemented yet"); - } - - @Override - public boolean hasCredential(String key, Object value) { - throw new CmsException("Not implemented yet"); - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrAuthorization.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrAuthorization.java deleted file mode 100644 index 3832a1568..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrAuthorization.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.argeo.cms.internal.useradmin; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.osgi.service.useradmin.Authorization; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -class JcrAuthorization implements Authorization { - private final String name; - private final List roles; - - public JcrAuthorization(UserDetails userDetails) { - this.name = userDetails.getUsername(); - List t = new ArrayList(); - for (GrantedAuthority ga : userDetails.getAuthorities()) { - t.add(ga.getAuthority()); - } - roles = Collections.unmodifiableList(t); - } - - @Override - public String getName() { - return name; - } - - @Override - public boolean hasRole(String name) { - return roles.contains(name); - } - - @Override - public String[] getRoles() { - return roles.toArray(new String[roles.size()]); - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrEndUser.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrEndUser.java deleted file mode 100644 index 921bff778..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrEndUser.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.argeo.cms.internal.useradmin; - -import org.argeo.security.jcr.JcrUserDetails; -import org.springframework.security.core.userdetails.UserDetails; - -class JcrEndUser extends AbstractJcrUser { - private final JcrUserDetails userDetails; - - public JcrEndUser(JcrUserDetails userDetails) { - super(userDetails.getUsername()); - this.userDetails = userDetails; - } - - UserDetails getUserDetails() { - return userDetails; - } - - public String toString() { - return "ArgeoUser: " + getName(); - } - - public boolean equals(Object obj) { - if (!(obj instanceof JcrEndUser)) - return false; - else - return ((JcrEndUser) obj).getName().equals(getName()); - } - - public int hashCode() { - return getName().hashCode(); - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrGroup.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrGroup.java deleted file mode 100644 index 56ddf0b42..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrGroup.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.argeo.cms.internal.useradmin; - -import org.argeo.cms.CmsException; -import org.osgi.service.useradmin.Group; -import org.osgi.service.useradmin.Role; - -class JcrGroup extends AbstractJcrUser implements Group { - public JcrGroup(String name) { - super(name); - } - - // - // OSGi MODEL - // - @Override - public int getType() { - return Role.GROUP; - } - - @Override - public boolean addMember(Role role) { - throw new CmsException("Not implemented yet"); - } - - @Override - public boolean addRequiredMember(Role role) { - throw new CmsException("Not implemented yet"); - } - - @Override - public boolean removeMember(Role role) { - throw new CmsException("Not implemented yet"); - } - - @Override - public Role[] getMembers() { - throw new CmsException("Not implemented yet"); - } - - @Override - public Role[] getRequiredMembers() { - throw new CmsException("Not implemented yet"); - } - - public String toString() { - return "ArgeoGroup: " + getName(); - } - - public boolean equals(Object obj) { - if (!(obj instanceof JcrGroup)) - return false; - else - return ((JcrGroup) obj).getName().equals(getName()); - } - - public int hashCode() { - return getName().hashCode(); - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrRole.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrRole.java deleted file mode 100644 index 7b3d6ed4e..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrRole.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.argeo.cms.internal.useradmin; - -import java.util.Dictionary; - -import org.osgi.service.useradmin.Role; - -abstract class JcrRole implements Role { - private String name; - - public JcrRole(String name) { - this.name = name; - } - - @Override - public String getName() { - return name; - } - - @Override - public int getType() { - return Role.ROLE; - } - - @Override - public Dictionary getProperties() { - return new JcrRoleProperties(); - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrRoleProperties.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrRoleProperties.java deleted file mode 100644 index 02d210062..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrRoleProperties.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.argeo.cms.internal.useradmin; - -import java.util.Dictionary; -import java.util.Enumeration; - -import org.argeo.cms.CmsException; - -/** Empty for the time being */ -class JcrRoleProperties extends Dictionary { - - @Override - public int size() { - return 0; - } - - @Override - public boolean isEmpty() { - return true; - } - - @Override - public Enumeration keys() { - return new KeyEnumeration(); - } - - @Override - public Enumeration elements() { - return new ValueEnumeration(); - } - - @Override - public Object get(Object key) { - return null; - } - - @Override - public Object put(String key, Object value) { - throw new CmsException("Not implemented yet"); - } - - @Override - public Object remove(Object key) { - return null; - } - - private class KeyEnumeration implements Enumeration { - - @Override - public boolean hasMoreElements() { - return false; - } - - @Override - public String nextElement() { - return null; - } - - } - - private class ValueEnumeration implements Enumeration { - - @Override - public boolean hasMoreElements() { - return false; - } - - @Override - public Object nextElement() { - return null; - } - - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrUserAdmin.java deleted file mode 100644 index f36a0714f..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/JcrUserAdmin.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.argeo.cms.internal.useradmin; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import javax.jcr.Repository; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.cms.CmsException; -import org.argeo.cms.internal.useradmin.jackrabbit.JackrabbitUserAdminService; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrUserDetails; -import org.argeo.security.jcr.NewUserDetails; -import org.osgi.framework.BundleContext; -import org.osgi.framework.InvalidSyntaxException; -import org.osgi.framework.ServiceReference; -import org.osgi.service.useradmin.Authorization; -import org.osgi.service.useradmin.Role; -import org.osgi.service.useradmin.User; -import org.osgi.service.useradmin.UserAdmin; -import org.osgi.service.useradmin.UserAdminEvent; -import org.osgi.service.useradmin.UserAdminListener; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - -/** - * Incomplete implementation of {@link UserAdmin} wrapping the supported - * {@link UserAdminService} for the time being. - */ -public class JcrUserAdmin implements UserAdmin { - private final BundleContext bundleContext; - private JackrabbitUserAdminService userAdminService; - - private final Session session; - - public JcrUserAdmin(BundleContext bundleContext, Repository node) { - try { - this.bundleContext = bundleContext; - this.session = node.login(); - } catch (Exception e) { - throw new ArgeoException("Cannot initialize user admin", e); - } - } - - public void destroy() { - JcrUtils.logoutQuietly(session); - } - - @Override - public Role createRole(String name, int type) { - if (Role.USER == type) { - NewUserDetails userDetails = new NewUserDetails(name, null); - userAdminService().createUser(userDetails); - return new JcrEndUser((JcrUserDetails) userAdminService() - .loadUserByUsername(name)); - } else if (Role.GROUP == type) { - userAdminService().newRole(name); - return new JcrGroup(name); - } else { - throw new ArgeoException("Unsupported role type " + type); - } - } - - @Override - public boolean removeRole(String name) { - Role role = getRole(name); - if (role == null) - return false; - if (role instanceof JcrEndUser) - userAdminService().deleteUser(role.getName()); - else if (role instanceof JcrGroup) - userAdminService().deleteRole(role.getName()); - else - return false; - return true; - } - - @Override - public Role getRole(String name) { - try { - JcrUserDetails userDetails = (JcrUserDetails) userAdminService() - .loadUserByUsername(name); - return new JcrEndUser(userDetails); - } catch (UsernameNotFoundException e) { - if (userAdminService().listEditableRoles().contains(name)) - return new JcrGroup(name); - else - return null; - } - } - - @Override - public Role[] getRoles(String filter) throws InvalidSyntaxException { - if (filter != null) - throw new ArgeoException("Filtering not yet implemented"); - List roles = new ArrayList(userAdminService() - .listEditableRoles()); - List users = new ArrayList(userAdminService() - .listUsers()); - Role[] res = new Role[users.size() + roles.size()]; - for (int i = 0; i < roles.size(); i++) - res[i] = new JcrGroup(roles.get(i)); - for (int i = 0; i < users.size(); i++) - res[roles.size() + i] = new JcrEndUser( - (JcrUserDetails) userAdminService().loadUserByUsername( - users.get(i))); - return res; - } - - @Override - public User getUser(String key, String value) { - throw new CmsException("Property based search not yet implemented"); - } - - @Override - public Authorization getAuthorization(User user) { - return new JcrAuthorization(((JcrEndUser) user).getUserDetails()); - } - - private synchronized UserAdminService userAdminService() { - return userAdminService; - } - - public void setUserAdminService(JackrabbitUserAdminService userAdminService) { - this.userAdminService = userAdminService; - } - - protected synchronized void notifyEvent(UserAdminEvent event) { - try { - Collection> sr = bundleContext - .getServiceReferences(UserAdminListener.class, null); - for (Iterator> it = sr - .iterator(); it.hasNext();) { - UserAdminListener listener = bundleContext - .getService(it.next()); - listener.roleChanged(event); - } - } catch (InvalidSyntaxException e) { - throw new ArgeoException("Cannot notify listeners", e); - } - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/OsJcrUserAdminService.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/OsJcrUserAdminService.java deleted file mode 100644 index 4ad2ad16d..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/OsJcrUserAdminService.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.cms.internal.auth.OsJcrAuthenticationProvider; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrUserDetails; -import org.springframework.dao.DataAccessException; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - -/** - * Dummy user service to be used when running as a single OS user (typically - * desktop). TODO integrate with JCR user / groups - */ -public class OsJcrUserAdminService implements UserAdminService { - private Repository repository; - - /** In memory roles provided by applications. */ - private List roles = new ArrayList(); - - // private Session adminSession; - - public void init() { - // try { - // adminSession = repository.login(); - // } catch (RepositoryException e) { - // throw new ArgeoException("Cannot initialize", e); - // } - } - - public void destroy() { - // JcrUtils.logoutQuietly(adminSession); - } - - /** Unsupported */ - public void createUser(UserDetails user) { - throw new UnsupportedOperationException(); - } - - /** Does nothing */ - public void updateUser(UserDetails user) { - - } - - /** Unsupported */ - public void deleteUser(String username) { - throw new UnsupportedOperationException(); - } - - /** Unsupported */ - public void changePassword(String oldPassword, String newPassword) { - throw new UnsupportedOperationException(); - } - - public boolean userExists(String username) { - if (getSPropertyUsername().equals(username)) - return true; - else - return false; - } - - public UserDetails loadUserByUsername(String username) - throws UsernameNotFoundException, DataAccessException { - if (getSPropertyUsername().equals(username)) { - UserDetails userDetails; - if (repository != null) { - Session adminSession = null; - try { - adminSession = repository.login(); - Node userProfile = UserJcrUtils.getUserProfile( - adminSession, username); - userDetails = new JcrUserDetails(userProfile, "", - OsJcrAuthenticationProvider.getBaseAuthorities()); - } catch (RepositoryException e) { - throw new ArgeoException( - "Cannot retrieve user profile for " + username, e); - } finally { - JcrUtils.logoutQuietly(adminSession); - } - } else { - userDetails = new User(username, "", true, true, true, true, - OsJcrAuthenticationProvider.getBaseAuthorities()); - } - return userDetails; - } else { - throw new UnsupportedOperationException(); - } - } - - protected final String getSPropertyUsername() { - return System.getProperty("user.name"); - } - - public Set listUsers() { - Set set = new HashSet(); - set.add(getSPropertyUsername()); - return set; - } - - public Set listUsersInRole(String role) { - Set set = new HashSet(); - set.add(getSPropertyUsername()); - return set; - } - - /** Does nothing */ - public void synchronize() { - } - - /** Unsupported */ - public void newRole(String role) { - roles.add(role); - } - - public Set listEditableRoles() { - return new HashSet(roles); - } - - /** Unsupported */ - public void deleteRole(String role) { - roles.remove(role); - } - - public void setRepository(Repository repository) { - this.repository = repository; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/SimpleJcrSecurityModel.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/SimpleJcrSecurityModel.java deleted file mode 100644 index 9d26f1335..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/SimpleJcrSecurityModel.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin; - -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.Value; -import javax.jcr.security.Privilege; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.core.security.user.UserAccessControlProvider; -import org.argeo.ArgeoException; -import org.argeo.cms.internal.auth.JcrSecurityModel; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; - -/** - * Manages data expected by the Argeo security model, such as user home and - * profile. - */ -public class SimpleJcrSecurityModel implements JcrSecurityModel { - private final static Log log = LogFactory - .getLog(SimpleJcrSecurityModel.class); - // ArgeoNames not implemented as interface in order to ease derivation by - // Jackrabbit bundles - - /** The home base path. */ - private String homeBasePath = "/home"; - private String peopleBasePath = ArgeoJcrConstants.PEOPLE_BASE_PATH; - - @Override - public void init(Session adminSession) throws RepositoryException { - JcrUtils.mkdirs(adminSession, homeBasePath); - JcrUtils.mkdirs(adminSession, peopleBasePath); - adminSession.save(); - - JcrUtils.addPrivilege(adminSession, homeBasePath, - UserAccessControlProvider.USER_ADMIN_GROUP_NAME, - Privilege.JCR_READ); - JcrUtils.addPrivilege(adminSession, peopleBasePath, - UserAccessControlProvider.USER_ADMIN_GROUP_NAME, - Privilege.JCR_ALL); - } - - public synchronized Node sync(Session session, String username, - List roles) { - // TODO check user name validity (e.g. should not start by ROLE_) - - try { - Node userHome = UserJcrUtils.getUserHome(session, username); - if (userHome == null) { - String homePath = generateUserPath(homeBasePath, username); - userHome = JcrUtils.mkdirs(session, homePath); - // userHome = JcrUtils.mkfolders(session, homePath); - userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME); - userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username); - session.save(); - - JcrUtils.clearAccessControList(session, homePath, username); - JcrUtils.addPrivilege(session, homePath, username, - Privilege.JCR_ALL); - } else { - // for backward compatibility with pre 1.0 security model - if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) { - userHome.getNode(ArgeoNames.ARGEO_PROFILE).remove(); - userHome.getSession().save(); - } - } - - // Remote roles - if (roles != null) { - // writeRemoteRoles(userHome, roles); - } - - Node userProfile = UserJcrUtils.getUserProfile(session, username); - // new user - if (userProfile == null) { - String personPath = generateUserPath(peopleBasePath, username); - Node personBase = JcrUtils.mkdirs(session, personPath); - userProfile = personBase.addNode(ArgeoNames.ARGEO_PROFILE); - userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE); - userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username); - userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, true); - userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED, - true); - userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED, - true); - userProfile.setProperty( - ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, true); - session.save(); - - JcrUtils.clearAccessControList(session, userProfile.getPath(), - username); - JcrUtils.addPrivilege(session, userProfile.getPath(), username, - Privilege.JCR_READ); - } - - // Remote roles - if (roles != null) { - writeRemoteRoles(userProfile, roles); - } - return userProfile; - } catch (RepositoryException e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot sync node security model for " - + username, e); - } - } - - /** Generate path for a new user home */ - protected String generateUserPath(String base, String username) { - int atIndex = username.indexOf('@'); - if (atIndex > 0) { - String domain = username.substring(0, atIndex); - String name = username.substring(atIndex + 1); - return base + '/' + JcrUtils.firstCharsToPath(domain, 2) + '/' - + domain + '/' + JcrUtils.firstCharsToPath(name, 2) + '/' - + name; - } else if (atIndex == 0 || atIndex == (username.length() - 1)) { - throw new ArgeoException("Unsupported username " + username); - } else { - return base + '/' + JcrUtils.firstCharsToPath(username, 2) + '/' - + username; - } - } - - /** Write remote roles used by remote access in the home directory */ - protected void writeRemoteRoles(Node userHome, List roles) - throws RepositoryException { - boolean writeRoles = false; - if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) { - Value[] remoteRoles = userHome.getProperty( - ArgeoNames.ARGEO_REMOTE_ROLES).getValues(); - if (remoteRoles.length != roles.size()) - writeRoles = true; - else - for (int i = 0; i < remoteRoles.length; i++) - if (!remoteRoles[i].getString().equals(roles.get(i))) - writeRoles = true; - } else - writeRoles = true; - - if (writeRoles) { - userHome.getSession().getWorkspace().getVersionManager() - .checkout(userHome.getPath()); - String[] roleIds = roles.toArray(new String[roles.size()]); - userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roleIds); - JcrUtils.updateLastModified(userHome); - userHome.getSession().save(); - userHome.getSession().getWorkspace().getVersionManager() - .checkin(userHome.getPath()); - if (log.isDebugEnabled()) - log.debug("Wrote remote roles " + roles + " for " - + userHome.getProperty(ArgeoNames.ARGEO_USER_ID)); - } - - } - - public void setHomeBasePath(String homeBasePath) { - this.homeBasePath = homeBasePath; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitSecurityModel.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitSecurityModel.java deleted file mode 100644 index de7f72466..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitSecurityModel.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin.jackrabbit; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.api.JackrabbitSession; -import org.apache.jackrabbit.api.security.user.Group; -import org.apache.jackrabbit.api.security.user.User; -import org.apache.jackrabbit.api.security.user.UserManager; -import org.argeo.ArgeoException; -import org.argeo.cms.internal.useradmin.SimpleJcrSecurityModel; -import org.argeo.jcr.ArgeoNames; - -/** Make sure that user authorizable exists before syncing user directories. */ -public class JackrabbitSecurityModel extends SimpleJcrSecurityModel { - private final static Log log = LogFactory - .getLog(JackrabbitSecurityModel.class); - - @Override - public synchronized Node sync(Session session, String username, - List roles) { - if (!(session instanceof JackrabbitSession)) - return super.sync(session, username, roles); - - try { - UserManager userManager = ((JackrabbitSession) session) - .getUserManager(); - User user = (User) userManager.getAuthorizable(username); - if (user != null) { - String principalName = user.getPrincipal().getName(); - if (!principalName.equals(username)) { - log.warn("Jackrabbit principal is '" + principalName - + "' but username is '" + username - + "'. Recreating..."); - user.remove(); - user = userManager.createUser(username, ""); - } - } else { - // create new principal - user = userManager.createUser(username, ""); - log.info(username + " added as Jackrabbit user " + user); - } - - // generic JCR sync - Node userProfile = super.sync(session, username, roles); - - Boolean enabled = userProfile.getProperty(ArgeoNames.ARGEO_ENABLED) - .getBoolean(); - if (enabled && user.isDisabled()) - user.disable(null); - else if (!enabled && !user.isDisabled()) - user.disable(userProfile.getPath() + " is disabled"); - - // Sync Jackrabbit roles - if (roles != null) - syncRoles(userManager, user, roles); - - return userProfile; - } catch (RepositoryException e) { - throw new ArgeoException( - "Cannot perform Jackrabbit specific operations", e); - } - } - - /** Make sure Jackrabbit roles are in line with authentication */ - void syncRoles(UserManager userManager, User user, List roles) - throws RepositoryException { - List userGroupIds = new ArrayList(); - for (String role : roles) { - Group group = (Group) userManager.getAuthorizable(role); - if (group == null) { - group = userManager.createGroup(role); - log.info(role + " added as " + group); - } - if (!group.isMember(user)) - group.addMember(user); - userGroupIds.add(role); - } - - // check if user has not been removed from some groups - for (Iterator it = user.declaredMemberOf(); it.hasNext();) { - Group group = it.next(); - if (!userGroupIds.contains(group.getID())) - group.removeMember(user); - } - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitUserAdminService.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitUserAdminService.java deleted file mode 100644 index cc6d85b48..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/JackrabbitUserAdminService.java +++ /dev/null @@ -1,473 +0,0 @@ -package org.argeo.cms.internal.useradmin.jackrabbit; - -import static org.argeo.cms.KernelHeader.ROLE_ADMIN; -import static org.argeo.cms.KernelHeader.USERNAME_ADMIN; -import static org.argeo.cms.KernelHeader.USERNAME_DEMO; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.SimpleCredentials; -import javax.jcr.version.VersionManager; - -import org.apache.jackrabbit.api.JackrabbitSession; -import org.apache.jackrabbit.api.security.user.Authorizable; -import org.apache.jackrabbit.api.security.user.Group; -import org.apache.jackrabbit.api.security.user.User; -import org.apache.jackrabbit.api.security.user.UserManager; -import org.apache.jackrabbit.core.security.authentication.CryptedSimpleCredentials; -import org.apache.jackrabbit.core.security.user.UserAccessControlProvider; -import org.argeo.ArgeoException; -import org.argeo.cms.CmsException; -import org.argeo.cms.KernelHeader; -import org.argeo.cms.internal.auth.GrantedAuthorityPrincipal; -import org.argeo.cms.internal.auth.JcrSecurityModel; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.security.NodeAuthenticationToken; -import org.argeo.security.SecurityUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrUserDetails; -import org.argeo.security.jcr.NewUserDetails; -import org.springframework.dao.DataAccessException; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - -/** - * An implementation of {@link UserAdminService} which closely wraps Jackrabbits - * implementation. Roles are implemented with Groups. - */ -public class JackrabbitUserAdminService implements UserAdminService, - AuthenticationProvider { - private final static String JACKR_ADMINISTRATORS = "administrators"; - private final static String REP_PRINCIPAL_NAME = "rep:principalName"; - // private final static String REP_PASSWORD = "rep:password"; - - private Repository repository; - private JcrSecurityModel securityModel; - - private JackrabbitSession adminSession = null; - - private String initialPassword = "demo"; - - public void init() throws RepositoryException { - Authentication authentication = SecurityContextHolder.getContext() - .getAuthentication(); - authentication.getName(); - adminSession = (JackrabbitSession) repository.login(); - Authorizable adminGroup = getUserManager().getAuthorizable(ROLE_ADMIN); - if (adminGroup == null) { - adminGroup = getUserManager().createGroup(ROLE_ADMIN); - adminSession.save(); - } - - // create superuser - Authorizable superUser = getUserManager().getAuthorizable( - USERNAME_ADMIN); - if (superUser == null) { - superUser = getUserManager().createUser(USERNAME_ADMIN, - initialPassword); - ((Group) adminGroup).addMember(superUser); - securityModel.sync(adminSession, USERNAME_ADMIN, null); - adminSession.save(); - - // create demo user only at initialisation - Authorizable demoUser = getUserManager().getAuthorizable( - USERNAME_DEMO); - if (demoUser != null) - throw new CmsException("There is already a demo user"); - demoUser = getUserManager().createUser(USERNAME_DEMO, - initialPassword); - securityModel.sync(adminSession, USERNAME_DEMO, null); - adminSession.save(); - } - securityModel.init(adminSession); - } - - public void destroy() throws RepositoryException { - JcrUtils.logoutQuietly(adminSession); - } - - private UserManager getUserManager() throws RepositoryException { - return adminSession.getUserManager(); - } - - @Override - public void createUser(UserDetails user) { - try { - // if (getUserManager().getAuthorizable(user.getUsername()) == null) - // { - getUserManager().createUser(user.getUsername(), user.getPassword()); - Node userProfile = securityModel.sync(adminSession, - user.getUsername(), null); - if (user instanceof NewUserDetails) - ((NewUserDetails) user).mapToProfileNode(userProfile); - userProfile.getSession().save(); - - // check in node - VersionManager versionManager = userProfile.getSession() - .getWorkspace().getVersionManager(); - if (versionManager.isCheckedOut(userProfile.getPath())) - versionManager.checkin(userProfile.getPath()); - // } - updateUser(user); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot create user " + user, e); - } - } - - @Override - public void updateUser(UserDetails userDetails) { - try { - String username = userDetails.getUsername(); - User user = (User) getUserManager().getAuthorizable(username); - if (user == null) - throw new ArgeoException("No user " + userDetails.getUsername()); - - // new password - String newPassword = userDetails.getPassword(); - if (!newPassword.trim().equals("")) { - if (newPassword.startsWith("{SHA-256}")) { - // Already hashed password - throw new CmsException("Cannot import hashed password"); - // Value v = adminSession.getValueFactory().createValue( - // newPassword); - // user.setProperty(REP_PASSWORD, v); - // TODO find a way to deal w/ protected property - // see - // http://jackrabbit.apache.org/api/2.2/org/apache/jackrabbit/core/security/user/UserImporter.html - } else { - SimpleCredentials sp = new SimpleCredentials( - userDetails.getUsername(), - newPassword.toCharArray()); - CryptedSimpleCredentials credentials = (CryptedSimpleCredentials) user - .getCredentials(); - - if (!credentials.matches(sp)) - user.changePassword(new String(newPassword)); - } - } - - List roles = new ArrayList(); - for (GrantedAuthority ga : userDetails.getAuthorities()) { - if (ga.getAuthority().equals(KernelHeader.ROLE_USER)) - continue; - roles.add(ga.getAuthority()); - } - - groups: for (Iterator it = user.memberOf(); it.hasNext();) { - Group group = it.next(); - String groupName = group.getPrincipal().getName(); - String role = groupNameToRole(groupName); - if (role == null) - continue groups; - - if (roles.contains(role)) - roles.remove(role); - else { - group.removeMember(user); - if (role.equals(KernelHeader.ROLE_ADMIN)) { - Group administratorsGroup = ((Group) getUserManager() - .getAuthorizable(JACKR_ADMINISTRATORS)); - if (administratorsGroup.isDeclaredMember(user)) - administratorsGroup.removeMember(user); - } - } - } - - // remaining (new memberships) - for (String role : roles) { - String groupName = roleToGroupName(role); - Group group = (Group) getUserManager().getAuthorizable( - groupName); - if (group == null) - throw new ArgeoException("Group " + role - + " does not exist," - + " whereas it was granted to user " + userDetails); - group.addMember(user); - - // add to Jackrabbit administrators - if (role.equals(KernelHeader.ROLE_ADMIN)) { - Group administratorsGroup = (Group) getUserManager() - .getAuthorizable(JACKR_ADMINISTRATORS); - administratorsGroup.addMember(user); - } - - } - } catch (Exception e) { - throw new ArgeoException("Cannot update user details", e); - } - - } - - @Override - public void deleteUser(String username) { - try { - getUserManager().getAuthorizable(username).remove(); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot remove user " + username, e); - } - } - - @Override - public void changePassword(String oldPassword, String newPassword) { - Authentication authentication = SecurityContextHolder.getContext() - .getAuthentication(); - String username = authentication.getName(); - try { - SimpleCredentials sp = new SimpleCredentials(username, - oldPassword.toCharArray()); - User user = (User) getUserManager().getAuthorizable(username); - CryptedSimpleCredentials credentials = (CryptedSimpleCredentials) user - .getCredentials(); - if (credentials.matches(sp)) - user.changePassword(newPassword); - else - throw new BadCredentialsException("Bad credentials provided"); - } catch (Exception e) { - throw new ArgeoException("Cannot change password for user " - + username, e); - } - } - - @Override - public boolean userExists(String username) { - try { - Authorizable authorizable = getUserManager().getAuthorizable( - username); - if (authorizable != null && authorizable instanceof User) - return true; - return false; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot check whether user " + username - + " exists ", e); - } - } - - @Override - public Set listUsers() { - LinkedHashSet res = new LinkedHashSet(); - try { - Iterator users = getUserManager().findAuthorizables( - "rep:principalName", null, UserManager.SEARCH_TYPE_USER); - while (users.hasNext()) { - res.add(users.next().getPrincipal().getName()); - } - return res; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot list users", e); - } - } - - @Override - public Set listUsersInRole(String role) { - LinkedHashSet res = new LinkedHashSet(); - try { - Group group = (Group) getUserManager().getAuthorizable(role); - Iterator users = group.getMembers(); - // NB: not recursive - while (users.hasNext()) { - res.add(users.next().getPrincipal().getName()); - } - return res; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot list users in role " + role, e); - } - } - - @Override - public void synchronize() { - } - - @Override - public void newRole(String role) { - try { - getUserManager().createGroup(role); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot create role " + role, e); - } - } - - @Override - public Set listEditableRoles() { - LinkedHashSet res = new LinkedHashSet(); - try { - Iterator groups = getUserManager().findAuthorizables( - REP_PRINCIPAL_NAME, null, UserManager.SEARCH_TYPE_GROUP); - while (groups.hasNext()) { - Group group = (Group) groups.next(); - String groupName = group.getPrincipal().getName(); - String role = groupNameToRole(groupName); - if (role != null - && !role.equals(KernelHeader.ROLE_GROUP_ADMIN) - && !(role.equals(KernelHeader.ROLE_ADMIN) && !SecurityUtils - .hasCurrentThreadAuthority(KernelHeader.ROLE_ADMIN))) - res.add(role); - } - return res; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot list groups", e); - } - } - - @Override - public void deleteRole(String role) { - try { - getUserManager().getAuthorizable(role).remove(); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot remove role " + role, e); - } - } - - protected String roleToGroupName(String role) { - String groupName; - if (role.equals(KernelHeader.ROLE_USER_ADMIN)) - groupName = UserAccessControlProvider.USER_ADMIN_GROUP_NAME; - else if (role.equals(KernelHeader.ROLE_GROUP_ADMIN)) - groupName = UserAccessControlProvider.GROUP_ADMIN_GROUP_NAME; - else - groupName = role; - return groupName; - } - - protected String groupNameToRole(String groupName) { - String role; - if (groupName.equals(UserAccessControlProvider.USER_ADMIN_GROUP_NAME)) { - role = KernelHeader.ROLE_USER_ADMIN; - } else if (groupName - .equals(UserAccessControlProvider.GROUP_ADMIN_GROUP_NAME)) { - role = KernelHeader.ROLE_GROUP_ADMIN; - } else if (groupName.equals(JACKR_ADMINISTRATORS)) { - return null; - } else { - role = groupName; - } - return role; - } - - @Override - public UserDetails loadUserByUsername(String username) - throws UsernameNotFoundException, DataAccessException { - try { - User user = (User) getUserManager().getAuthorizable(username); - if (user == null) - throw new UsernameNotFoundException("User " + username - + " cannot be found"); - return loadJcrUserDetails(adminSession, username); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot load user " + username, e); - } - } - - protected JcrUserDetails loadJcrUserDetails(Session session, String username) - throws RepositoryException { - if (username == null) - username = session.getUserID(); - User user = (User) getUserManager().getAuthorizable(username); - - ArrayList authorities = new ArrayList(); - authorities.add(new GrantedAuthorityPrincipal(KernelHeader.ROLE_USER)); - - Group adminGroup = (Group) getUserManager().getAuthorizable( - KernelHeader.ROLE_ADMIN); - - Iterator groups; - if (username.equals(KernelHeader.USERNAME_ADMIN) - || adminGroup.isDeclaredMember(user)) { - groups = getUserManager().findAuthorizables(REP_PRINCIPAL_NAME, - null, UserManager.SEARCH_TYPE_GROUP); - } else { - groups = user.declaredMemberOf(); - } - - while (groups.hasNext()) { - Authorizable group = groups.next(); - String groupName = group.getPrincipal().getName(); - String role = groupNameToRole(groupName); - if (role != null) - authorities.add(new GrantedAuthorityPrincipal(role)); - } - - Node userProfile = UserJcrUtils.getUserProfile(session, username); - JcrUserDetails userDetails = new JcrUserDetails(userProfile, "", - authorities); - return userDetails; - } - - // AUTHENTICATION PROVIDER - public synchronized Authentication authenticate( - Authentication authentication) throws AuthenticationException { - NodeAuthenticationToken siteAuth = (NodeAuthenticationToken) authentication; - String username = siteAuth.getName(); - if (!(siteAuth.getCredentials() instanceof char[])) - throw new ArgeoException("Only char array passwords are supported"); - char[] password = (char[]) siteAuth.getCredentials(); - try { - SimpleCredentials sp = new SimpleCredentials(siteAuth.getName(), - password); - User user = (User) getUserManager().getAuthorizable(username); - if (user == null) - throw new BadCredentialsException("Bad credentials"); - CryptedSimpleCredentials credentials = (CryptedSimpleCredentials) user - .getCredentials(); - // String providedPassword = siteAuth.getCredentials().toString(); - if (!credentials.matches(sp)) - throw new BadCredentialsException("Bad credentials"); - - // session = repository.login(sp, null); - - Node userProfile = UserJcrUtils.getUserProfile(adminSession, - username); - JcrUserDetails.checkAccountStatus(userProfile); - } catch (BadCredentialsException e) { - throw e; - } catch (Exception e) { - throw new BadCredentialsException( - "Cannot authenticate " + siteAuth, e); - } finally { - Arrays.fill(password, '*'); - } - - try { - JcrUserDetails userDetails = loadJcrUserDetails(adminSession, - username); - NodeAuthenticationToken authenticated = new NodeAuthenticationToken( - siteAuth, userDetails.getAuthorities()); - authenticated.setDetails(userDetails); - return authenticated; - } catch (RepositoryException e) { - throw new ArgeoException( - "Unexpected exception when authenticating " + siteAuth, e); - } - } - - @SuppressWarnings("rawtypes") - public boolean supports(Class authentication) { - return UsernamePasswordAuthenticationToken.class - .isAssignableFrom(authentication); - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - - public void setSecurityModel(JcrSecurityModel securityModel) { - this.securityModel = securityModel; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/ScopedSessionProvider.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/ScopedSessionProvider.java deleted file mode 100644 index dcb139939..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/jackrabbit/ScopedSessionProvider.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin.jackrabbit; - -import java.io.Serializable; - -import javax.jcr.LoginException; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jackrabbit.server.SessionProvider; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrConstants; -import org.argeo.jcr.JcrUtils; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; - -/** - * Session provider assuming a single workspace and a short life cycle, - * typically a Spring bean of scope (web) 'session'. - */ -public class ScopedSessionProvider implements SessionProvider, Serializable { - private static final long serialVersionUID = 6589775984177317058L; - private static final Log log = LogFactory - .getLog(ScopedSessionProvider.class); - private transient HttpSession httpSession = null; - private transient Session jcrSession = null; - - private transient String currentRepositoryName = null; - private transient String currentWorkspaceName = null; - private transient String currentJcrUser = null; - - // private transient String anonymousUserId = "anonymous"; - - public Session getSession(HttpServletRequest request, Repository rep, - String workspace) throws LoginException, ServletException, - RepositoryException { - - Authentication authentication = SecurityContextHolder.getContext() - .getAuthentication(); - if (authentication == null) - throw new ArgeoException( - "Request not authenticated by Spring Security"); - String springUser = authentication.getName(); - - // HTTP - String requestJcrRepository = (String) request - .getAttribute(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS); - - // HTTP session - if (httpSession != null - && !httpSession.getId().equals(request.getSession().getId())) - throw new ArgeoException( - "Only session scope is supported in this mode"); - if (httpSession == null) - httpSession = request.getSession(); - - // Initializes current values - if (currentRepositoryName == null) - currentRepositoryName = requestJcrRepository; - if (currentWorkspaceName == null) - currentWorkspaceName = workspace; - if (currentJcrUser == null) - currentJcrUser = springUser; - - // logout if there was a change in session coordinates - if (jcrSession != null) - if (!currentRepositoryName.equals(requestJcrRepository)) { - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() + " Changed from repository '" - + currentRepositoryName + "' to '" - + requestJcrRepository - + "', logging out cached JCR session."); - logout(); - } else if (!currentWorkspaceName.equals(workspace)) { - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() + " Changed from workspace '" - + currentWorkspaceName + "' to '" + workspace - + "', logging out cached JCR session."); - logout(); - } else if (!currentJcrUser.equals(springUser)) { - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() + " Changed from user '" - + currentJcrUser + "' to '" + springUser - + "', logging out cached JCR session."); - logout(); - } - - // login if needed - if (jcrSession == null) - try { - Session session = login(rep, workspace); - if (!session.getUserID().equals(springUser)) { - JcrUtils.logoutQuietly(session); - throw new ArgeoException("Spring Security user '" - + springUser + "' not in line with JCR user '" - + session.getUserID() + "'"); - } - currentRepositoryName = requestJcrRepository; - // do not use workspace variable which may be null - currentWorkspaceName = session.getWorkspace().getName(); - currentJcrUser = session.getUserID(); - - jcrSession = session; - return jcrSession; - } catch (RepositoryException e) { - throw new ArgeoException("Cannot open session to workspace " - + workspace, e); - } - - // returns cached session - return jcrSession; - } - - protected Session login(Repository repository, String workspace) - throws RepositoryException { - Session session = repository.login(workspace); - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() + " User '" + session.getUserID() - + "' logged in workspace '" - + session.getWorkspace().getName() + "' of repository '" - + currentRepositoryName + "'"); - return session; - } - - public void releaseSession(Session session) { - if (log.isTraceEnabled()) - log.trace(getHttpSessionId() + " Releasing JCR session " + session); - } - - protected void logout() { - JcrUtils.logoutQuietly(jcrSession); - jcrSession = null; - } - - protected final String getHttpSessionId() { - return httpSession != null ? httpSession.getId() : ""; - } - - public void init() { - } - - public void destroy() { - logout(); - if (getHttpSessionId() != null) - if (log.isDebugEnabled()) - log.debug(getHttpSessionId() - + " Cleaned up provider for web session "); - httpSession = null; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoLdapShaPasswordEncoder.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoLdapShaPasswordEncoder.java deleted file mode 100644 index a1d25e92c..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoLdapShaPasswordEncoder.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin.ldap; - -import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder; - -/** - * {@link LdapShaPasswordEncoder} allowing to configure the usage of salt (APache - * Directory Server 1.0 does not support bind with SSHA) - */ -public class ArgeoLdapShaPasswordEncoder extends LdapShaPasswordEncoder { - private Boolean useSalt = true; - - @Override - public String encodePassword(String rawPass, Object salt) { - return super.encodePassword(rawPass, useSalt ? salt : null); - } - - public void setUseSalt(Boolean useSalt) { - this.useSalt = useSalt; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoLdapUserDetailsManager.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoLdapUserDetailsManager.java deleted file mode 100644 index 4381fa991..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoLdapUserDetailsManager.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin.ldap; - -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Random; -import java.util.Set; -import java.util.TreeSet; - -import org.argeo.ArgeoException; -import org.argeo.security.UserAdminService; -import org.springframework.ldap.core.ContextSource; -import org.springframework.security.authentication.encoding.PasswordEncoder; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.ldap.userdetails.LdapUserDetailsManager; - -/** Extends {@link LdapUserDetailsManager} by adding password encoding support. */ -@SuppressWarnings("deprecation") -public class ArgeoLdapUserDetailsManager extends LdapUserDetailsManager - implements UserAdminService { - private String superUsername = "root"; - private ArgeoUserAdminDaoLdap userAdminDao; - private PasswordEncoder passwordEncoder; - private final Random random; - - public ArgeoLdapUserDetailsManager(ContextSource contextSource) { - super(contextSource); - this.random = createRandom(); - } - - private static Random createRandom() { - try { - return SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - return new Random(System.currentTimeMillis()); - } - } - - @Override - public void changePassword(String oldPassword, String newPassword) { - Authentication authentication = SecurityContextHolder.getContext() - .getAuthentication(); - if (authentication == null) - throw new ArgeoException( - "Cannot change password without authentication"); - String username = authentication.getName(); - UserDetails userDetails = loadUserByUsername(username); - String currentPassword = userDetails.getPassword(); - if (currentPassword == null) - throw new ArgeoException("Cannot access current password"); - if (!passwordEncoder - .isPasswordValid(currentPassword, oldPassword, null)) - throw new ArgeoException("Old password invalid"); - // Spring Security LDAP 2.0 is buggy when used with OpenLDAP and called - // with oldPassword argument - super.changePassword(null, encodePassword(newPassword)); - } - - public void newRole(String role) { - userAdminDao.createRole(role, superUsername); - } - - public void synchronize() { - for (String username : userAdminDao.listUsers()) - loadUserByUsername(username); - // TODO: find a way to remove from JCR - } - - public void deleteRole(String role) { - userAdminDao.deleteRole(role); - } - - public Set listUsers() { - return userAdminDao.listUsers(); - } - - public Set listUsersInRole(String role) { - Set lst = new TreeSet( - userAdminDao.listUsersInRole(role)); - Iterator it = lst.iterator(); - while (it.hasNext()) { - if (it.next().equals(superUsername)) { - it.remove(); - break; - } - } - return lst; - } - - public List listUserRoles(String username) { - UserDetails userDetails = loadUserByUsername(username); - List roles = new ArrayList(); - for (GrantedAuthority ga : userDetails.getAuthorities()) { - roles.add(ga.getAuthority()); - } - return Collections.unmodifiableList(roles); - } - - public Set listEditableRoles() { - return userAdminDao.listEditableRoles(); - } - - protected String encodePassword(String password) { - if (!password.startsWith("{")) { - byte[] salt = new byte[16]; - random.nextBytes(salt); - return passwordEncoder.encodePassword(password, salt); - } else { - return password; - } - } - - public void setPasswordEncoder(PasswordEncoder passwordEncoder) { - this.passwordEncoder = passwordEncoder; - } - - public void setSuperUsername(String superUsername) { - this.superUsername = superUsername; - } - - public void setUserAdminDao(ArgeoUserAdminDaoLdap userAdminDao) { - this.userAdminDao = userAdminDao; - } - -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoUserAdminDaoLdap.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoUserAdminDaoLdap.java deleted file mode 100644 index faead2e76..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/ArgeoUserAdminDaoLdap.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin.ldap; - -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; - -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; - -import org.springframework.ldap.core.ContextExecutor; -import org.springframework.ldap.core.ContextMapper; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DistinguishedName; -import org.springframework.ldap.core.LdapTemplate; -import org.springframework.ldap.core.support.BaseLdapPathContextSource; -import org.springframework.security.ldap.LdapUsernameToDnMapper; -import org.springframework.security.ldap.LdapUtils; - -/** - * Wraps low-level LDAP operation on user and roles, used by - * {@link ArgeoLdapUserDetailsManager} - */ -public class ArgeoUserAdminDaoLdap { - private String userBase; - private String usernameAttribute; - private String groupBase; - private String[] groupClasses; - - private String groupRoleAttribute; - private String groupMemberAttribute; - private String defaultRole; - private String rolePrefix; - - private final LdapTemplate ldapTemplate; - private LdapUsernameToDnMapper usernameMapper; - - /** - * Standard constructor, using the LDAP context source shared with Spring - * Security components. - */ - public ArgeoUserAdminDaoLdap(BaseLdapPathContextSource contextSource) { - this.ldapTemplate = new LdapTemplate(contextSource); - } - - @SuppressWarnings("unchecked") - public synchronized Set listUsers() { - List usernames = (List) ldapTemplate.listBindings( - new DistinguishedName(userBase), new ContextMapper() { - public Object mapFromContext(Object ctxArg) { - DirContextAdapter ctx = (DirContextAdapter) ctxArg; - return ctx.getStringAttribute(usernameAttribute); - } - }); - - return Collections - .unmodifiableSortedSet(new TreeSet(usernames)); - } - - @SuppressWarnings("unchecked") - public Set listEditableRoles() { - return Collections.unmodifiableSortedSet(new TreeSet( - ldapTemplate.listBindings(groupBase, new ContextMapper() { - public Object mapFromContext(Object ctxArg) { - String groupName = ((DirContextAdapter) ctxArg) - .getStringAttribute(groupRoleAttribute); - String roleName = convertGroupToRole(groupName); - return roleName; - } - }))); - } - - @SuppressWarnings("unchecked") - public Set listUsersInRole(String role) { - return (Set) ldapTemplate.lookup( - buildGroupDn(convertRoleToGroup(role)), new ContextMapper() { - public Object mapFromContext(Object ctxArg) { - DirContextAdapter ctx = (DirContextAdapter) ctxArg; - String[] userDns = ctx - .getStringAttributes(groupMemberAttribute); - TreeSet set = new TreeSet(); - for (String userDn : userDns) { - DistinguishedName dn = new DistinguishedName(userDn); - String username = dn.getValue(usernameAttribute); - set.add(username); - } - return Collections.unmodifiableSortedSet(set); - } - }); - } - - public void createRole(String role, final String superuserName) { - String group = convertRoleToGroup(role); - DistinguishedName superuserDn = (DistinguishedName) ldapTemplate - .executeReadWrite(new ContextExecutor() { - public Object executeWithContext(DirContext ctx) - throws NamingException { - return LdapUtils.getFullDn( - usernameMapper.buildDn(superuserName), ctx); - } - }); - - Name groupDn = buildGroupDn(group); - DirContextAdapter context = new DirContextAdapter(); - context.setAttributeValues("objectClass", groupClasses); - context.setAttributeValue("cn", group); - // Add superuser because cannot create empty group - context.setAttributeValue(groupMemberAttribute, superuserDn.toString()); - ldapTemplate.bind(groupDn, context, null); - } - - public void deleteRole(String role) { - String group = convertRoleToGroup(role); - Name dn = buildGroupDn(group); - ldapTemplate.unbind(dn); - } - - /** Maps a role (ROLE_XXX) to the related LDAP group (xxx) */ - protected String convertRoleToGroup(String role) { - String group = role; - if (group.startsWith(rolePrefix)) { - group = group.substring(rolePrefix.length()); - group = group.toLowerCase(); - } - return group; - } - - /** Maps anLDAP group (xxx) to the related role (ROLE_XXX) */ - protected String convertGroupToRole(String groupName) { - groupName = groupName.toUpperCase(); - - return rolePrefix + groupName; - } - - protected Name buildGroupDn(String name) { - return new DistinguishedName(groupRoleAttribute + "=" + name + "," - + groupBase); - } - - public void setUserBase(String userBase) { - this.userBase = userBase; - } - - public void setUsernameAttribute(String usernameAttribute) { - this.usernameAttribute = usernameAttribute; - } - - public void setGroupBase(String groupBase) { - this.groupBase = groupBase; - } - - public void setGroupRoleAttribute(String groupRoleAttributeName) { - this.groupRoleAttribute = groupRoleAttributeName; - } - - public void setGroupMemberAttribute(String groupMemberAttributeName) { - this.groupMemberAttribute = groupMemberAttributeName; - } - - public void setDefaultRole(String defaultRole) { - this.defaultRole = defaultRole; - } - - public void setRolePrefix(String rolePrefix) { - this.rolePrefix = rolePrefix; - } - - public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) { - this.usernameMapper = usernameMapper; - } - - public String getDefaultRole() { - return defaultRole; - } - - public void setGroupClasses(String[] groupClasses) { - this.groupClasses = groupClasses; - } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/JcrLdapSynchronizer.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/JcrLdapSynchronizer.java deleted file mode 100644 index ce8b37337..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/JcrLdapSynchronizer.java +++ /dev/null @@ -1,623 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin.ldap; - -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.SortedSet; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.query.Query; -import javax.jcr.version.VersionManager; -import javax.naming.Name; -import javax.naming.directory.BasicAttribute; -import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.cms.internal.auth.JcrSecurityModel; -import org.argeo.cms.internal.useradmin.SimpleJcrSecurityModel; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.ArgeoTypes; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.SecurityUtils; -import org.argeo.security.jcr.JcrUserDetails; -import org.springframework.ldap.core.ContextMapper; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DirContextOperations; -import org.springframework.ldap.core.DistinguishedName; -import org.springframework.ldap.core.LdapTemplate; -import org.springframework.security.authentication.encoding.PasswordEncoder; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.ldap.LdapUsernameToDnMapper; -import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; - -/** Makes sure that LDAP and JCR are in line. */ -@SuppressWarnings("deprecation") -public class JcrLdapSynchronizer implements UserDetailsContextMapper, - ArgeoNames { - private final static Log log = LogFactory.getLog(JcrLdapSynchronizer.class); - - // LDAP - private LdapTemplate ldapTemplate; - /** - * LDAP template whose context source has an object factory set to null. see - * this - */ - // private LdapTemplate rawLdapTemplate; - - private String userBase; - private String usernameAttribute; - private String passwordAttribute; - private String[] userClasses; - // private String defaultUserRole ="ROLE_USER"; - - // private NamingListener ldapUserListener; - // private SearchControls subTreeSearchControls; - private LdapUsernameToDnMapper usernameMapper; - - private PasswordEncoder passwordEncoder; - private final Random random; - - // JCR - /** Admin session on the main workspace */ - private Session nodeSession; - private Repository repository; - - // private JcrProfileListener jcrProfileListener; - private JcrSecurityModel jcrSecurityModel = new SimpleJcrSecurityModel(); - - // Mapping - private Map propertyToAttributes = new HashMap(); - - public JcrLdapSynchronizer() { - random = createRandom(); - } - - public void init() { - try { - nodeSession = repository.login(); - - // TODO put this in a different thread, and poll the LDAP server - // until it is up - try { - synchronize(); - - // LDAP - // subTreeSearchControls = new SearchControls(); - // subTreeSearchControls - // .setSearchScope(SearchControls.SUBTREE_SCOPE); - // LDAP listener - // ldapUserListener = new LdapUserListener(); - // rawLdapTemplate.executeReadOnly(new ContextExecutor() { - // public Object executeWithContext(DirContext ctx) - // throws NamingException { - // EventDirContext ectx = (EventDirContext) ctx.lookup(""); - // ectx.addNamingListener(userBase, "(" - // + usernameAttribute + "=*)", - // subTreeSearchControls, ldapUserListener); - // return null; - // } - // }); - } catch (Exception e) { - log.error("Could not synchronize and listen to LDAP," - + " probably because the LDAP server is not available." - + " Restart the system as soon as possible.", e); - } - - // JCR - // String[] nodeTypes = { ArgeoTypes.ARGEO_USER_PROFILE }; - // jcrProfileListener = new JcrProfileListener(); - // noLocal is used so that we are not notified when we modify JCR - // from LDAP - // nodeSession - // .getWorkspace() - // .getObservationManager() - // .addEventListener(jcrProfileListener, - // Event.PROPERTY_CHANGED | Event.NODE_ADDED, "/", - // true, null, nodeTypes, true); - } catch (Exception e) { - JcrUtils.logoutQuietly(nodeSession); - throw new ArgeoException("Cannot initialize LDAP/JCR synchronizer", - e); - } - } - - public void destroy() { - // JcrUtils.removeListenerQuietly(nodeSession, jcrProfileListener); - JcrUtils.logoutQuietly(nodeSession); - // try { - // rawLdapTemplate.executeReadOnly(new ContextExecutor() { - // public Object executeWithContext(DirContext ctx) - // throws NamingException { - // EventDirContext ectx = (EventDirContext) ctx.lookup(""); - // ectx.removeNamingListener(ldapUserListener); - // return null; - // } - // }); - // } catch (Exception e) { - // // silent (LDAP server may have been shutdown already) - // if (log.isTraceEnabled()) - // log.trace("Cannot remove LDAP listener", e); - // } - } - - /* - * LDAP TO JCR - */ - /** Full synchronization between LDAP and JCR. LDAP has priority. */ - protected void synchronize() { - try { - Name userBaseName = new DistinguishedName(userBase); - // TODO subtree search? - @SuppressWarnings("unchecked") - List userPaths = (List) ldapTemplate.listBindings( - userBaseName, new ContextMapper() { - public Object mapFromContext(Object ctxObj) { - try { - return mapLdapToJcr((DirContextAdapter) ctxObj); - } catch (Exception e) { - // do not break process because of error - log.error( - "Could not LDAP->JCR synchronize user " - + ctxObj, e); - return null; - } - } - }); - - // create accounts which are not in LDAP - Query query = nodeSession - .getWorkspace() - .getQueryManager() - .createQuery( - "select * from [" + ArgeoTypes.ARGEO_USER_PROFILE - + "]", Query.JCR_SQL2); - NodeIterator it = query.execute().getNodes(); - while (it.hasNext()) { - Node userProfile = it.nextNode(); - String path = userProfile.getPath(); - try { - if (!userPaths.contains(path)) { - String username = userProfile - .getProperty(ARGEO_USER_ID).getString(); - // GrantedAuthority[] authorities = {new - // GrantedAuthorityImpl(defaultUserRole)}; - List authorities = new ArrayList(); - JcrUserDetails userDetails = new JcrUserDetails( - userProfile, username, authorities); - String dn = createLdapUser(userDetails); - log.warn("Created ldap entry '" + dn + "' for user '" - + username + "'"); - - // if(!userProfile.getProperty(ARGEO_ENABLED).getBoolean()){ - // continue profiles; - // } - // - // log.warn("Path " - // + path - // + " not found in LDAP, disabling user " - // + userProfile.getProperty(ArgeoNames.ARGEO_USER_ID) - // .getString()); - - // Temporary hack to repair previous behaviour - if (!userProfile.getProperty(ARGEO_ENABLED) - .getBoolean()) { - VersionManager versionManager = nodeSession - .getWorkspace().getVersionManager(); - versionManager.checkout(userProfile.getPath()); - userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, - true); - nodeSession.save(); - versionManager.checkin(userProfile.getPath()); - } - } - } catch (Exception e) { - log.error("Cannot process " + path, e); - } - } - } catch (Exception e) { - JcrUtils.discardQuietly(nodeSession); - log.error("Cannot synchronize LDAP and JCR", e); - // throw new ArgeoException("Cannot synchronize LDAP and JCR", e); - } - } - - private String createLdapUser(UserDetails user) { - DirContextAdapter ctx = new DirContextAdapter(); - mapUserToContext(user, ctx); - DistinguishedName dn = usernameMapper.buildDn(user.getUsername()); - ldapTemplate.bind(dn, ctx, null); - return dn.toString(); - } - - /** Called during authentication in order to retrieve user details */ - public UserDetails mapUserFromContext(final DirContextOperations ctx, - final String username, - Collection authorities) { - if (ctx == null) - throw new ArgeoException("No LDAP information for user " + username); - - String ldapUsername = ctx.getStringAttribute(usernameAttribute); - if (!ldapUsername.equals(username)) - throw new ArgeoException("Logged in with username " + username - + " but LDAP user is " + ldapUsername); - - Node userProfile = jcrSecurityModel.sync(nodeSession, username, - SecurityUtils.authoritiesToStringList(authorities)); - // JcrUserDetails.checkAccountStatus(userProfile); - - // password - SortedSet passwordAttributes = ctx - .getAttributeSortedStringSet(passwordAttribute); - String password; - if (passwordAttributes == null || passwordAttributes.size() == 0) { - // throw new ArgeoException("No password found for user " + - // username); - password = "NULL"; - } else { - byte[] arr = (byte[]) passwordAttributes.first(); - password = new String(arr); - // erase password - Arrays.fill(arr, (byte) 0); - } - - try { - return new JcrUserDetails(userProfile, password, authorities); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot retrieve user details for " - + username, e); - } - } - - /** - * Writes an LDAP context to the JCR user profile. - * - * @return path to user profile - */ - protected synchronized String mapLdapToJcr(DirContextAdapter ctx) { - Session session = nodeSession; - try { - // process - String username = ctx.getStringAttribute(usernameAttribute); - - Node userProfile = jcrSecurityModel.sync(session, username, null); - Map modifications = new HashMap(); - for (String jcrProperty : propertyToAttributes.keySet()) - ldapToJcr(userProfile, jcrProperty, ctx, modifications); - - int modifCount = modifications.size(); - if (modifCount > 0) { - session.getWorkspace().getVersionManager() - .checkout(userProfile.getPath()); - for (String prop : modifications.keySet()) - userProfile.setProperty(prop, modifications.get(prop)); - JcrUtils.updateLastModified(userProfile); - session.save(); - session.getWorkspace().getVersionManager() - .checkin(userProfile.getPath()); - if (log.isDebugEnabled()) - log.debug("Mapped " + modifCount + " LDAP modification" - + (modifCount == 1 ? "" : "s") + " from " - + ctx.getDn() + " to " + userProfile); - } - return userProfile.getPath(); - } catch (Exception e) { - JcrUtils.discardQuietly(session); - throw new ArgeoException("Cannot synchronize JCR and LDAP", e); - } - } - - /** Maps an LDAP property to a JCR property */ - protected void ldapToJcr(Node userProfile, String jcrProperty, - DirContextOperations ctx, Map modifications) { - // TODO do we really need DirContextOperations? - try { - String ldapAttribute; - if (propertyToAttributes.containsKey(jcrProperty)) - ldapAttribute = propertyToAttributes.get(jcrProperty); - else - throw new ArgeoException( - "No LDAP attribute mapped for JCR proprty " - + jcrProperty); - - String value = ctx.getStringAttribute(ldapAttribute); - String jcrValue = userProfile.hasProperty(jcrProperty) ? userProfile - .getProperty(jcrProperty).getString() : null; - if (value != null && jcrValue != null) { - if (!value.equals(jcrValue)) - modifications.put(jcrProperty, value); - } else if (value != null && jcrValue == null) { - modifications.put(jcrProperty, value); - } else if (value == null && jcrValue != null) { - modifications.put(jcrProperty, value); - } - } catch (Exception e) { - throw new ArgeoException("Cannot map JCR property " + jcrProperty - + " from LDAP", e); - } - } - - /* - * JCR to LDAP - */ - - public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) { - if (!(user instanceof JcrUserDetails)) - throw new ArgeoException("Unsupported user details: " - + user.getClass()); - - ctx.setAttributeValues("objectClass", userClasses); - ctx.setAttributeValue(usernameAttribute, user.getUsername()); - ctx.setAttributeValue(passwordAttribute, - encodePassword(user.getPassword())); - - final JcrUserDetails jcrUserDetails = (JcrUserDetails) user; - try { - Node userProfile = nodeSession - .getNode(jcrUserDetails.getHomePath()).getNode( - ARGEO_PROFILE); - for (String jcrProperty : propertyToAttributes.keySet()) { - if (userProfile.hasProperty(jcrProperty)) { - ModificationItem mi = jcrToLdap(jcrProperty, userProfile - .getProperty(jcrProperty).getString()); - if (mi != null) - ctx.setAttribute(mi.getAttribute()); - } - } - if (log.isTraceEnabled()) - log.trace("Mapped " + userProfile + " to " + ctx.getDn()); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot synchronize JCR and LDAP", e); - } - - } - - /** Maps a JCR property to an LDAP property */ - protected ModificationItem jcrToLdap(String jcrProperty, String value) { - // TODO do we really need DirContextOperations? - try { - String ldapAttribute; - if (propertyToAttributes.containsKey(jcrProperty)) - ldapAttribute = propertyToAttributes.get(jcrProperty); - else - return null; - - // fix issue with empty 'sn' in LDAP - if (ldapAttribute.equals("sn") && (value.trim().equals(""))) - return null; - // fix issue with empty 'description' in LDAP - if (ldapAttribute.equals("description") && value.trim().equals("")) - return null; - BasicAttribute attr = new BasicAttribute( - propertyToAttributes.get(jcrProperty), value); - ModificationItem mi = new ModificationItem( - DirContext.REPLACE_ATTRIBUTE, attr); - return mi; - } catch (Exception e) { - throw new ArgeoException("Cannot map JCR property " + jcrProperty - + " from LDAP", e); - } - } - - /* - * UTILITIES - */ - protected String encodePassword(String password) { - if (!password.startsWith("{")) { - byte[] salt = new byte[16]; - random.nextBytes(salt); - return passwordEncoder.encodePassword(password, salt); - } else { - return password; - } - } - - private static Random createRandom() { - try { - return SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - return new Random(System.currentTimeMillis()); - } - } - - /* - * DEPENDENCY INJECTION - */ - - public void setLdapTemplate(LdapTemplate ldapTemplate) { - this.ldapTemplate = ldapTemplate; - } - - public void setRawLdapTemplate(LdapTemplate rawLdapTemplate) { - // this.rawLdapTemplate = rawLdapTemplate; - } - - public void setRepository(Repository repository) { - this.repository = repository; - } - - public void setUserBase(String userBase) { - this.userBase = userBase; - } - - public void setUsernameAttribute(String usernameAttribute) { - this.usernameAttribute = usernameAttribute; - } - - public void setPropertyToAttributes(Map propertyToAttributes) { - this.propertyToAttributes = propertyToAttributes; - } - - public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) { - this.usernameMapper = usernameMapper; - } - - public void setPasswordAttribute(String passwordAttribute) { - this.passwordAttribute = passwordAttribute; - } - - public void setUserClasses(String[] userClasses) { - this.userClasses = userClasses; - } - - public void setPasswordEncoder(PasswordEncoder passwordEncoder) { - this.passwordEncoder = passwordEncoder; - } - - public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) { - this.jcrSecurityModel = jcrSecurityModel; - } - - /** Listen to LDAP */ - // class LdapUserListener implements ObjectChangeListener, - // NamespaceChangeListener, UnsolicitedNotificationListener { - // - // public void namingExceptionThrown(NamingExceptionEvent evt) { - // evt.getException().printStackTrace(); - // } - // - // public void objectChanged(NamingEvent evt) { - // Binding user = evt.getNewBinding(); - // // TODO find a way not to be called when JCR is the source of the - // // modification - // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate - // .lookup(user.getName()); - // mapLdapToJcr(ctx); - // } - // - // public void objectAdded(NamingEvent evt) { - // Binding user = evt.getNewBinding(); - // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate - // .lookup(user.getName()); - // mapLdapToJcr(ctx); - // } - // - // public void objectRemoved(NamingEvent evt) { - // if (log.isDebugEnabled()) - // log.debug(evt); - // } - // - // public void objectRenamed(NamingEvent evt) { - // if (log.isDebugEnabled()) - // log.debug(evt); - // } - // - // public void notificationReceived(UnsolicitedNotificationEvent evt) { - // UnsolicitedNotification notification = evt.getNotification(); - // NamingException ne = notification.getException(); - // String msg = "LDAP notification " + "ID=" + notification.getID() - // + ", referrals=" + notification.getReferrals(); - // if (ne != null) { - // if (log.isTraceEnabled()) - // log.trace(msg + ", exception= " + ne, ne); - // else - // log.warn(msg + ", exception= " + ne); - // } else if (log.isDebugEnabled()) { - // log.debug("Unsollicited LDAP notification " + msg); - // } - // } - // - // } - - /** Listen to JCR */ - // class JcrProfileListener implements EventListener { - // - // public void onEvent(EventIterator events) { - // try { - // final Map> modifications = new HashMap>(); - // while (events.hasNext()) { - // Event event = events.nextEvent(); - // try { - // if (Event.PROPERTY_CHANGED == event.getType()) { - // Property property = (Property) nodeSession - // .getItem(event.getPath()); - // String propertyName = property.getName(); - // Node userProfile = property.getParent(); - // String username = userProfile.getProperty( - // ARGEO_USER_ID).getString(); - // if (propertyToAttributes.containsKey(propertyName)) { - // Name name = usernameMapper.buildDn(username); - // if (!modifications.containsKey(name)) - // modifications.put(name, - // new ArrayList()); - // String value = property.getString(); - // ModificationItem mi = jcrToLdap(propertyName, - // value); - // if (mi != null) - // modifications.get(name).add(mi); - // } - // } else if (Event.NODE_ADDED == event.getType()) { - // Node userProfile = nodeSession.getNode(event - // .getPath()); - // String username = userProfile.getProperty( - // ARGEO_USER_ID).getString(); - // Name name = usernameMapper.buildDn(username); - // for (String propertyName : propertyToAttributes - // .keySet()) { - // if (!modifications.containsKey(name)) - // modifications.put(name, - // new ArrayList()); - // String value = userProfile.getProperty( - // propertyName).getString(); - // ModificationItem mi = jcrToLdap(propertyName, - // value); - // if (mi != null) - // modifications.get(name).add(mi); - // } - // } - // } catch (RepositoryException e) { - // throw new ArgeoException("Cannot process event " - // + event, e); - // } - // } - // - // for (Name name : modifications.keySet()) { - // List userModifs = modifications.get(name); - // int modifCount = userModifs.size(); - // ldapTemplate.modifyAttributes(name, userModifs - // .toArray(new ModificationItem[modifCount])); - // if (log.isDebugEnabled()) - // log.debug("Mapped " + modifCount + " JCR modification" - // + (modifCount == 1 ? "" : "s") + " to " + name); - // } - // } catch (Exception e) { - // // if (log.isDebugEnabled()) - // // e.printStackTrace(); - // throw new ArgeoException("Cannot process JCR events (" - // + e.getMessage() + ")", e); - // } - // } - // - // } -} diff --git a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/JcrUserDetailsContextMapper.java b/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/JcrUserDetailsContextMapper.java deleted file mode 100644 index acfcebc11..000000000 --- a/org.argeo.cms/src/org/argeo/cms/internal/useradmin/ldap/JcrUserDetailsContextMapper.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.cms.internal.useradmin.ldap; - -import java.util.Collection; -import java.util.UUID; - -import javax.jcr.Node; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrUtils; -import org.argeo.jcr.UserJcrUtils; -import org.argeo.security.jcr.JcrUserDetails; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DirContextOperations; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.ldap.userdetails.UserDetailsContextMapper; - -/** @deprecated Read only mapping from LDAP to user details */ -@Deprecated -public class JcrUserDetailsContextMapper implements UserDetailsContextMapper, - ArgeoNames { - /** Admin session on the security workspace */ - private Session securitySession; - private Repository repository; - private String securityWorkspace = "security"; - - public void init() { - try { - securitySession = repository.login(securityWorkspace); - } catch (RepositoryException e) { - JcrUtils.logoutQuietly(securitySession); - throw new ArgeoException( - "Cannot initialize LDAP/JCR user details context mapper", e); - } - } - - public void destroy() { - JcrUtils.logoutQuietly(securitySession); - } - - /** Called during authentication in order to retrieve user details */ - public UserDetails mapUserFromContext(final DirContextOperations ctx, - final String username, - Collection authorities) { - if (ctx == null) - throw new ArgeoException("No LDAP information for user " + username); - Node userHome = UserJcrUtils.getUserHome(securitySession, username); - if (userHome == null) - throw new ArgeoException("No JCR information for user " + username); - - // password - // SortedSet passwordAttributes = ctx - // .getAttributeSortedStringSet(passwordAttribute); - // String password; - // if (passwordAttributes == null || passwordAttributes.size() == 0) { - // throw new ArgeoException("No password found for user " + username); - // } else { - // byte[] arr = (byte[]) passwordAttributes.first(); - // password = new String(arr); - // // erase password - // Arrays.fill(arr, (byte) 0); - // } - - try { - // we don't have access to password, so let's not pretend - String password = UUID.randomUUID().toString(); - return new JcrUserDetails(userHome.getNode(ARGEO_PROFILE), - password, authorities); - } catch (RepositoryException e) { - throw new ArgeoException("Cannot retrieve user details for " - + username, e); - } - } - - public void mapUserToContext(UserDetails user, final DirContextAdapter ctx) { - throw new UnsupportedOperationException("LDAP access is read-only"); - } - -} diff --git a/org.argeo.security.core/bnd.bnd b/org.argeo.security.core/bnd.bnd index 4d6f374a1..d3d44a195 100644 --- a/org.argeo.security.core/bnd.bnd +++ b/org.argeo.security.core/bnd.bnd @@ -1,7 +1,7 @@ Bundle-ActivationPolicy: lazy Import-Package:org.bouncycastle.*;resolution:=optional,\ -org.springframework.util,\ javax.jcr.security,\ org.apache.commons.codec,\ org.apache.commons.codec.digest,\ +org.springframework.core,\ * diff --git a/org.argeo.security.core/build.properties b/org.argeo.security.core/build.properties index 1047348bb..436b925a8 100644 --- a/org.argeo.security.core/build.properties +++ b/org.argeo.security.core/build.properties @@ -1,5 +1,4 @@ source.. = src/,\ ext/test/ additional.bundles = org.junit,\ - org.slf4j.commons.logging,\ - org.springframework.security.core + org.slf4j.commons.logging diff --git a/org.argeo.security.core/ext/test/org/argeo/security/PasswordSandbox.java b/org.argeo.security.core/ext/test/org/argeo/security/PasswordSandbox.java deleted file mode 100644 index de9a1eb1e..000000000 --- a/org.argeo.security.core/ext/test/org/argeo/security/PasswordSandbox.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security; - -import org.apache.commons.codec.DecoderException; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.binary.Hex; -import org.springframework.security.authentication.encoding.LdapShaPasswordEncoder; - -public class PasswordSandbox { - public static void main(String[] args) { - try { - // Tested password - String pwdPlain = "demo"; - - // Check Java generated values - LdapShaPasswordEncoder lspe = new LdapShaPasswordEncoder(); - String pwdLdapShaBase64 = lspe.encodePassword(pwdPlain, null); - System.out.println("pwdLdapShaBase64:\t\t" + pwdLdapShaBase64); - - String pwdShaBase64 = pwdLdapShaBase64.substring("{SHA}".length()); - System.out.println("pwdShaBase64:\t\t\t" + pwdShaBase64); - - byte[] pwdShaArray = Base64.decodeBase64(pwdShaBase64.getBytes()); - String pwdShaHex = new String(Hex.encodeHex(pwdShaArray)); - System.out.println("pwdShaHex:\t\t\t" + pwdShaHex); - - // Check that we can use JavaScript generated values in Hex - String jsShaHex = "89e495e7941cf9e40e6980d14a16bf023ccd4c91"; - System.out.println("jsShaHex:\t\t\t" + pwdShaHex); - System.out.println("pwdShaHex==jsShaHex:\t\t" - + (pwdShaHex.equals(jsShaHex))); - - byte[] jsShaArray = Hex.decodeHex(jsShaHex.toCharArray()); - String jsShaBase64 = new String(Base64.encodeBase64(jsShaArray)); - System.out.println("jsShaBase64:\t\t\t" + jsShaBase64); - System.out.println("pwdShaBase64==jsShaBase64:\t" - + (pwdShaBase64.equals(jsShaBase64))); - } catch (DecoderException e) { - e.printStackTrace(); - } - - } - -} \ No newline at end of file diff --git a/org.argeo.security.core/src/org/argeo/security/NodeAuthenticationToken.java b/org.argeo.security.core/src/org/argeo/security/NodeAuthenticationToken.java deleted file mode 100644 index 600811d75..000000000 --- a/org.argeo.security.core/src/org/argeo/security/NodeAuthenticationToken.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security; - -import java.util.Collection; - -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; - -/** Credentials required for the authentication to a node. */ -public class NodeAuthenticationToken extends - UsernamePasswordAuthenticationToken { - private static final long serialVersionUID = 1955222132884795213L; - private final String url; - - /** Non authenticated local constructor */ - public NodeAuthenticationToken(Object principal, Object credentials) { - super(principal, credentials); - this.url = null; - } - - /** Non authenticated remote constructor */ - public NodeAuthenticationToken(Object principal, Object credentials, - String url) { - super(principal, credentials); - this.url = url; - } - - /** Authenticated constructor */ - public NodeAuthenticationToken(NodeAuthenticationToken sat, - Collection authorities) { - super(sat.getPrincipal(), sat.getCredentials(), authorities); - this.url = sat.getUrl(); - } - - public String getUrl() { - return url; - } - - public Boolean isRemote() { - return url != null; - } - - public String toString() { - String username = getName(); - StringBuilder buf = new StringBuilder("groups="); - for (GrantedAuthority ga : getAuthorities()) { - if (!ga.getAuthority().equals(username)) { - buf.append(ga.getAuthority()); - buf.append(','); - } - } - buf.deleteCharAt(buf.length() - 1); - return "uid=" + getName() + " " + buf.toString(); - } -} diff --git a/org.argeo.security.core/src/org/argeo/security/OsAuthenticationToken.java b/org.argeo.security.core/src/org/argeo/security/OsAuthenticationToken.java deleted file mode 100644 index 5b71394dd..000000000 --- a/org.argeo.security.core/src/org/argeo/security/OsAuthenticationToken.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security; - -import java.security.AccessController; -import java.security.Principal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; - -import javax.security.auth.Subject; - -import org.argeo.ArgeoException; -import org.argeo.OperatingSystem; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -/** Abstracts principals provided by com.sun.security.auth.module login modules. */ -public class OsAuthenticationToken implements Authentication { - private static final long serialVersionUID = -7544626794250917244L; - - final Class osUserPrincipalClass; - final Class osUserIdPrincipalClass; - final Class osGroupIdPrincipalClass; - - private List grantedAuthorities; - - private UserDetails details; - - /** Request */ - public OsAuthenticationToken( - Collection authorities) { - this.grantedAuthorities = new ArrayList(authorities); - ClassLoader cl = getClass().getClassLoader(); - switch (OperatingSystem.os) { - case OperatingSystem.WINDOWS: - osUserPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.NTUserPrincipal"); - osUserIdPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.NTSidUserPrincipal"); - osGroupIdPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.NTSidGroupPrincipal"); - break; - case OperatingSystem.NIX: - osUserPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.UnixPrincipal"); - osUserIdPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.UnixNumericUserPrincipal"); - osGroupIdPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.UnixNumericGroupPrincipal"); - break; - case OperatingSystem.SOLARIS: - osUserPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.SolarisPrincipal"); - osUserIdPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.SolarisNumericUserPrincipal"); - osGroupIdPrincipalClass = getPrincipalClass(cl, - "com.sun.security.auth.SolarisNumericGroupPrincipal"); - break; - - default: - throw new ArgeoException("Unsupported operating system " - + OperatingSystem.os); - } - - } - - /** Authenticated */ - public OsAuthenticationToken() { - this(new ArrayList()); - } - - /** @return the name, or null if not yet logged */ - public String getName() { - Subject subject = Subject.getSubject(AccessController.getContext()); - if (subject == null) - return null; - return getUser().getName(); - } - - /** - * Should not be called during authentication since group IDs are not yet - * available {@link Subject} has been set - */ - public Collection getAuthorities() { - // grantedAuthorities should not be null at this stage - List gas = new ArrayList( - grantedAuthorities); - for (Principal groupPrincipal : getGroupsIds()) { - gas.add(new SimpleGrantedAuthority("OSGROUP_" - + groupPrincipal.getName())); - } - return gas; - } - - public UserDetails getDetails() { - return details; - } - - public void setDetails(UserDetails details) { - this.details = details; - } - - public boolean isAuthenticated() { - return grantedAuthorities != null; - } - - public void setAuthenticated(boolean isAuthenticated) - throws IllegalArgumentException { - if (grantedAuthorities != null) - grantedAuthorities.clear(); - grantedAuthorities = null; - } - - @SuppressWarnings("unchecked") - protected static Class getPrincipalClass( - ClassLoader cl, String className) { - try { - return (Class) cl.loadClass(className); - } catch (ClassNotFoundException e) { - throw new ArgeoException("Cannot load principal class", e); - } - } - - public Object getPrincipal() { - return getUser(); - } - - public Principal getUser() { - Subject subject = getSubject(); - Set userPrincipals = subject - .getPrincipals(osUserPrincipalClass); - if (userPrincipals == null || userPrincipals.size() == 0) - throw new ArgeoException("No OS principal"); - if (userPrincipals.size() > 1) - throw new ArgeoException("More than one OS principal"); - Principal user = userPrincipals.iterator().next(); - return user; - } - - public Principal getUserId() { - Subject subject = getSubject(); - Set userIdsPrincipals = subject - .getPrincipals(osUserIdPrincipalClass); - if (userIdsPrincipals == null || userIdsPrincipals.size() == 0) - throw new ArgeoException("No user id principal"); - if (userIdsPrincipals.size() > 1) - throw new ArgeoException("More than one user id principal"); - Principal userId = userIdsPrincipals.iterator().next(); - return userId; - } - - public Set getGroupsIds() { - Subject subject = getSubject(); - return (Set) subject - .getPrincipals(osGroupIdPrincipalClass); - } - - /** @return the subject always non null */ - protected Subject getSubject() { - Subject subject = Subject.getSubject(AccessController.getContext()); - if (subject == null) - throw new ArgeoException("No subject in JAAS context"); - return subject; - } - - public Object getCredentials() { - return ""; - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/SecurityUtils.java b/org.argeo.security.core/src/org/argeo/security/SecurityUtils.java index 2d453d3da..b3b0f37f3 100644 --- a/org.argeo.security.core/src/org/argeo/security/SecurityUtils.java +++ b/org.argeo.security.core/src/org/argeo/security/SecurityUtils.java @@ -15,16 +15,17 @@ */ package org.argeo.security; -import java.util.ArrayList; -import java.util.Collection; +import java.security.AccessController; +import java.security.Principal; +import java.security.acl.Group; import java.util.Collections; -import java.util.List; +import java.util.HashSet; +import java.util.Set; -import org.springframework.security.authentication.AnonymousAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; +import javax.security.auth.Subject; +import javax.security.auth.x500.X500Principal; + +import org.argeo.ArgeoException; /** Static utilities */ public final class SecurityUtils { @@ -33,16 +34,7 @@ public final class SecurityUtils { /** Whether the current thread has the admin role */ public static boolean hasCurrentThreadAuthority(String authority) { - SecurityContext securityContext = SecurityContextHolder.getContext(); - if (securityContext != null) { - Authentication authentication = securityContext.getAuthentication(); - if (authentication != null) { - for (GrantedAuthority ga : authentication.getAuthorities()) - if (ga.getAuthority().equals(authority)) - return true; - } - } - return false; + return roles().contains(authority); } /** @@ -50,49 +42,32 @@ public final class SecurityUtils { * anonymous */ public static String getCurrentThreadUsername() { - SecurityContext securityContext = SecurityContextHolder.getContext(); - if (securityContext != null) { - Authentication authentication = securityContext.getAuthentication(); - if (authentication != null) { - if (authentication instanceof AnonymousAuthenticationToken) { - return null; - } - return authentication.getName(); - } - } - return null; + return getUsername(); } - /** - * Returns the display name of the user details (by calling toString() on - * it) - */ - public static String getUserDetailsDisplayName() { - SecurityContext securityContext = SecurityContextHolder.getContext(); - if (securityContext != null) { - Authentication authentication = securityContext.getAuthentication(); - if (authentication != null) { - if (authentication instanceof AnonymousAuthenticationToken) { - return null; - } - Object details = authentication.getDetails(); - if (details != null) - return details.toString(); - return authentication.getName(); - } - } - return null; + public final static String getUsername() { + Subject subject = Subject.getSubject(AccessController.getContext()); + if (subject == null) + return null; + if (subject.getPrincipals(X500Principal.class).size() != 1) + return null; + Principal principal = subject.getPrincipals(X500Principal.class) + .iterator().next(); + return principal.getName(); + } - /** - * Converts an array of Spring Security {@link GrantedAuthority} to a - * read-only list of strings, for portability and integration - */ - public static List authoritiesToStringList( - Collection authorities) { - List lst = new ArrayList(); - for (GrantedAuthority ga : authorities) - lst.add(ga.getAuthority()); - return Collections.unmodifiableList(lst); + public final static Set roles() { + Set roles = Collections.synchronizedSet(new HashSet()); + Subject subject = Subject.getSubject(AccessController.getContext()); + if (subject == null) + throw new ArgeoException("Not authenticated."); + X500Principal userPrincipal = subject + .getPrincipals(X500Principal.class).iterator().next(); + roles.add(userPrincipal.getName()); + for (Principal group : subject.getPrincipals(Group.class)) { + roles.add(group.getName()); + } + return roles; } } diff --git a/org.argeo.security.core/src/org/argeo/security/SystemAuthentication.java b/org.argeo.security.core/src/org/argeo/security/SystemAuthentication.java deleted file mode 100644 index d489761e5..000000000 --- a/org.argeo.security.core/src/org/argeo/security/SystemAuthentication.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security; - -/** - * Marks a system authentication, that is which did not require a login process. - */ -public interface SystemAuthentication { - /** 'admin' for consistency with JCR */ - public final static String USERNAME_SYSTEM = "admin"; - public final static String ROLE_SYSTEM = "ROLE_SYSTEM"; - public final static String SYSTEM_KEY_PROPERTY = "argeo.security.systemKey"; -} diff --git a/org.argeo.security.core/src/org/argeo/security/SystemExecutionService.java b/org.argeo.security.core/src/org/argeo/security/SystemExecutionService.java deleted file mode 100644 index 075a6c3d8..000000000 --- a/org.argeo.security.core/src/org/argeo/security/SystemExecutionService.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security; - -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.concurrent.Future; - -/** - * Allows to execute code authenticated as a system user (that is not a real - * person). The {@link Executor} interface is not used directly in order to - * allow future extension of this interface and to simplify its publication - * (e.g. as an OSGi service) and interception. - */ -public interface SystemExecutionService extends Executor { - /** - * Executes this {@link Runnable} within a system authenticated context. - * Implementations should make sure that this method is properly secured via - * Java permissions since it could access everything without credentials. - */ - public void execute(Runnable runnable); - - /** - * Executes this {@link Callable} within a system authenticated context. - * Implementations should make sure that this method is properly secured via - * Java permissions since it could access everything without credentials. - */ - public Future submit(Callable task); -} diff --git a/org.argeo.security.core/src/org/argeo/security/UserAdminService.java b/org.argeo.security.core/src/org/argeo/security/UserAdminService.java deleted file mode 100644 index 8a391ff9f..000000000 --- a/org.argeo.security.core/src/org/argeo/security/UserAdminService.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security; - -import java.util.Set; - -import org.springframework.security.provisioning.UserDetailsManager; - -/** Enrich {@link UserDetailsManager} in order to provide roles semantics. */ -public interface UserAdminService extends UserDetailsManager { - /** - * Usernames must match this regexp pattern ({@value #USERNAME_PATTERN}). - * Thanks to this tip (modified to add upper-case, add '@') - */ - //public final static String USERNAME_PATTERN = "^[a-zA-Z0-9_-@]{3,64}$"; - - /** - * Email addresses must match this regexp pattern ({@value #EMAIL_PATTERN}. - * Thanks to this tip. - */ - public final static String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; - - /* - * USERS - */ - /** List all users. */ - public Set listUsers(); - - /** List users having this role (except the super user). */ - public Set listUsersInRole(String role); - - /** Synchronize with the underlying DAO. */ - public void synchronize(); - - /* - * ROLES - */ - public void newRole(String role); - - public Set listEditableRoles(); - - public void deleteRole(String role); -} diff --git a/org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java b/org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java index 42cf42eef..81eeadf21 100644 --- a/org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java +++ b/org.argeo.security.core/src/org/argeo/security/core/AbstractSystemExecution.java @@ -22,26 +22,15 @@ import javax.security.auth.login.LoginException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.ArgeoException; -import org.springframework.security.authentication.AuthenticationManager; /** Provides base method for executing code with system authorization. */ public abstract class AbstractSystemExecution { private final static Log log = LogFactory .getLog(AbstractSystemExecution.class); - // private AuthenticationManager authenticationManager; private final Subject subject = new Subject(); - // private String systemAuthenticationKey; private final String loginModule = "SYSTEM"; - /** Whether the current thread was authenticated by this component. */ - // private ThreadLocal authenticatedBySelf = new - // ThreadLocal() { - // protected Boolean initialValue() { - // return false; - // } - // }; - /** * Authenticate the calling thread to the underlying * {@link AuthenticationManager} @@ -53,33 +42,6 @@ public abstract class AbstractSystemExecution { } catch (LoginException e) { throw new ArgeoException("Cannot login as system", e); } - // if (authenticatedBySelf.get()) - // return; - // SecurityContext securityContext = SecurityContextHolder.getContext(); - // Authentication currentAuth = securityContext.getAuthentication(); - // if (currentAuth != null) { - // if (!(currentAuth instanceof SystemAuthentication)) - // throw new ArgeoException( - // "System execution on an already authenticated thread: " - // + currentAuth + ", THREAD=" - // + Thread.currentThread().getId()); - // return; - // } - // - // String key = systemAuthenticationKey != null ? - // systemAuthenticationKey - // : System.getProperty( - // SystemAuthentication.SYSTEM_KEY_PROPERTY, - // InternalAuthentication.SYSTEM_KEY_DEFAULT); - // if (key == null) - // throw new ArgeoException("No system key defined"); - // if (authenticationManager == null) - // throw new ArgeoException("Authentication manager cannot be null."); - // Authentication auth = authenticationManager - // .authenticate(new InternalAuthentication(key)); - // securityContext.setAuthentication(auth); - // - // authenticatedBySelf.set(true); if (log.isTraceEnabled()) log.trace("System authenticated"); } @@ -96,22 +58,4 @@ public abstract class AbstractSystemExecution { protected Subject getSubject() { return subject; } - - // /** - // * Whether the current thread was authenticated by this component or a - // * parent thread. - // */ - // protected Boolean isAuthenticatedBySelf() { - // return authenticatedBySelf.get(); - // } - // - public void setAuthenticationManager( - AuthenticationManager authenticationManager) { - log.warn("Use of authenticationManager is deprecated, remove this property from the configuration."); - } - - public void setSystemAuthenticationKey(String systemAuthenticationKey) { - log.warn("Use of systemAuthenticationKey is deprecated, remove this property from the configuration."); - // this.systemAuthenticationKey = systemAuthenticationKey; - } } diff --git a/org.argeo.security.core/src/org/argeo/security/core/AsyncSystemTaskExecutor.java b/org.argeo.security.core/src/org/argeo/security/core/AsyncSystemTaskExecutor.java deleted file mode 100644 index 0e400c82d..000000000 --- a/org.argeo.security.core/src/org/argeo/security/core/AsyncSystemTaskExecutor.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.core; - -import org.argeo.security.SystemExecutionService; -import org.springframework.core.task.SimpleAsyncTaskExecutor; - -/** - * Asynchronous Spring TaskExecutor (for use in JMS for example) wrapping a - * {@link SystemExecutionService}. - */ -public class AsyncSystemTaskExecutor extends SimpleAsyncTaskExecutor { - private static final long serialVersionUID = -8035527542087963068L; - - private SystemExecutionService systemExecutionService; - - public AsyncSystemTaskExecutor() { - super(); - } - - public AsyncSystemTaskExecutor(String threadNamePrefix) { - super(threadNamePrefix); - } - - @Override - public Thread createThread(final Runnable runnable) { - Runnable systemExecutionRunnable = new Runnable() { - - public void run() { - systemExecutionService.execute(runnable); - - } - }; - return super.createThread(systemExecutionRunnable); - } - - public void setSystemExecutionService( - SystemExecutionService systemExecutionService) { - this.systemExecutionService = systemExecutionService; - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/core/AuthenticatedApplicationContextInitialization.java b/org.argeo.security.core/src/org/argeo/security/core/AuthenticatedApplicationContextInitialization.java index 6c477ee9f..aa3827c92 100644 --- a/org.argeo.security.core/src/org/argeo/security/core/AuthenticatedApplicationContextInitialization.java +++ b/org.argeo.security.core/src/org/argeo/security/core/AuthenticatedApplicationContextInitialization.java @@ -15,7 +15,6 @@ */ package org.argeo.security.core; -import java.beans.PropertyDescriptor; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; @@ -25,97 +24,36 @@ import javax.security.auth.Subject; import org.eclipse.gemini.blueprint.context.DependencyInitializationAwareBeanPostProcessor; import org.springframework.beans.BeansException; -import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.support.AbstractBeanFactory; import org.springframework.beans.factory.support.SecurityContextProvider; import org.springframework.beans.factory.support.SimpleSecurityContextProvider; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ApplicationEvent; -import org.springframework.context.ApplicationListener; -import org.springframework.context.event.ContextRefreshedEvent; /** * Executes with a system authentication the instantiation and initialization * methods of the application context where it has been defined. */ public class AuthenticatedApplicationContextInitialization extends - AbstractSystemExecution implements DependencyInitializationAwareBeanPostProcessor, - ApplicationListener, ApplicationContextAware { - // private Log log = LogFactory - // .getLog(AuthenticatedApplicationContextInitialization.class); + AbstractSystemExecution implements + DependencyInitializationAwareBeanPostProcessor, ApplicationContextAware { /** If non empty, restricts to these beans */ private List beanNames = new ArrayList(); -// @SuppressWarnings("rawtypes") -// public Object postProcessBeforeInstantiation(Class beanClass, -// String beanName) throws BeansException { -// // we authenticate when any bean is instantiated -// // we will deauthenticate only when the application context has been -// // refreshed in order to be able to deal with factory beans has well -// // if (!isAuthenticatedBySelf()) { -// // if (beanNames.size() == 0) -// // authenticateAsSystem(); -// // else if (beanNames.contains(beanName)) -// // authenticateAsSystem(); -// // } -// return null; -// } -// -// public boolean postProcessAfterInstantiation(Object bean, String beanName) -// throws BeansException { -// return true; -// } -// -// public PropertyValues postProcessPropertyValues(PropertyValues pvs, -// PropertyDescriptor[] pds, Object bean, String beanName) -// throws BeansException { -// return pvs; -// } - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (beanNames.size() == 0 || beanNames.contains(beanName)) authenticateAsSystem(); - // try { - // if (beanNames.size() == 0 || beanNames.contains(beanName)) { - // LoginContext lc = new LoginContext("INIT", subject); - // lc.login(); - // } - // } catch (LoginException e) { - // throw new ArgeoException("Cannot login as initialization", e); - // } return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - // NOTE: in case there was an exception in on the initialization method - // we expect the underlying thread to die and thus the system - // authentication to be lost. We have currently no way to catch the - // exception and perform the deauthentication by ourselves. if (beanNames.size() == 0 || beanNames.contains(beanName)) deauthenticateAsSystem(); - // try { - // if (beanNames.size() == 0 || beanNames.contains(beanName)) { - // LoginContext lc = new LoginContext("INIT", subject); - // lc.logout(); - // } - // } catch (LoginException e) { - // // TODO Auto-generated catch block - // e.printStackTrace(); - // } return bean; } - public void onApplicationEvent(ApplicationEvent event) { - if (event instanceof ContextRefreshedEvent) { - // make sure that we have deauthenticated after the application - // context was initialized/refreshed - // deauthenticateAsSystem(); - } - } - public void setBeanNames(List beanNames) { this.beanNames = beanNames; } diff --git a/org.argeo.security.core/src/org/argeo/security/core/AuthenticationProvidersRegister.java b/org.argeo.security.core/src/org/argeo/security/core/AuthenticationProvidersRegister.java deleted file mode 100644 index e001f4c2d..000000000 --- a/org.argeo.security.core/src/org/argeo/security/core/AuthenticationProvidersRegister.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.core; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.InitializingBean; - -/** - * Maintains a list of authentication providers injected in to a provider - * manager, in order to avoid issues with OSGi services and use packages. - */ -@Deprecated -public class AuthenticationProvidersRegister implements InitializingBean { - private Log log = LogFactory.getLog(AuthenticationProvidersRegister.class); - - private List providers = new ArrayList(); - private List defaultProviders = new ArrayList(); - - public void register(Object authenticationProvider, - Map parameters) { - providers.add(authenticationProvider); - if (log.isTraceEnabled()) - log.trace("Registered authentication provider " + parameters); - } - - public void unregister(Object authenticationProvider, - Map parameters) { - providers.remove(authenticationProvider); - if (log.isTraceEnabled()) - log.trace("Unregistered authentication provider " + parameters); - } - - public List getProviders() { - return providers; - } - - public void setDefaultProviders( - List defaultProviders) { - this.defaultProviders = defaultProviders; - } - - public void afterPropertiesSet() throws Exception { - providers.addAll(defaultProviders); - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/core/InternalAuthentication.java b/org.argeo.security.core/src/org/argeo/security/core/InternalAuthentication.java deleted file mode 100644 index 31e29d18d..000000000 --- a/org.argeo.security.core/src/org/argeo/security/core/InternalAuthentication.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.core; - -import java.util.Collections; - -import org.argeo.security.SystemAuthentication; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - -/** A token base on a system key used to request a system authentication. */ -public class InternalAuthentication extends UsernamePasswordAuthenticationToken - implements SystemAuthentication { - private static final long serialVersionUID = -6783376375615949315L; - public final static String SYSTEM_KEY_DEFAULT = "argeo"; - - public InternalAuthentication(String key, String systemUsername, - String systemRole) { - super(systemUsername, key, Collections - .singleton(new SimpleGrantedAuthority(systemRole))); - } - - public InternalAuthentication(String key) { - this(key, SystemAuthentication.USERNAME_SYSTEM, SystemAuthentication.ROLE_SYSTEM); - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/core/InternalAuthenticationProvider.java b/org.argeo.security.core/src/org/argeo/security/core/InternalAuthenticationProvider.java deleted file mode 100644 index 4b7e047ba..000000000 --- a/org.argeo.security.core/src/org/argeo/security/core/InternalAuthenticationProvider.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.argeo.security.core; - -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; - -public class InternalAuthenticationProvider implements AuthenticationProvider { - private String key; - - public InternalAuthenticationProvider() { - } - - public InternalAuthenticationProvider(String key) { - this.key = key; - } - - @Override - public Authentication authenticate(Authentication arg0) - throws AuthenticationException { - InternalAuthentication authentication = (InternalAuthentication) arg0; - if (authentication.getCredentials().toString().equals(key)) - return authentication; - return null; - } - - public void setKey(String key) { - this.key = key; - } - - @Override - public boolean supports(Class authentication) { - return InternalAuthentication.class.isAssignableFrom(authentication); - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/core/KeyBasedSystemExecutionService.java b/org.argeo.security.core/src/org/argeo/security/core/KeyBasedSystemExecutionService.java deleted file mode 100644 index 6c85df1d1..000000000 --- a/org.argeo.security.core/src/org/argeo/security/core/KeyBasedSystemExecutionService.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.core; - -import java.util.concurrent.Callable; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; - -import org.argeo.ArgeoException; -import org.argeo.security.SystemExecutionService; - -/** - * Implementation of a {@link SystemExecutionService} using a key-based - * {@link InternalAuthentication} - */ -public class KeyBasedSystemExecutionService extends AbstractSystemExecution - implements SystemExecutionService { - public void execute(Runnable runnable) { - try { - wrapWithSystemAuthentication(Executors.callable(runnable)).call(); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new ArgeoException( - "Exception when running system authenticated task", e); - } - } - - public Future submit(Callable task) { - FutureTask future = new FutureTask( - wrapWithSystemAuthentication(task)); - future.run(); - return future; - } - - protected Callable wrapWithSystemAuthentication( - final Callable runnable) { - return new Callable() { - - public T call() throws Exception { - authenticateAsSystem(); - try { - return runnable.call(); - } finally { -// deauthenticateAsSystem(); - } - } - }; - } -} diff --git a/org.argeo.security.core/src/org/argeo/security/core/MatchingAuthenticationProvider.java b/org.argeo.security.core/src/org/argeo/security/core/MatchingAuthenticationProvider.java deleted file mode 100644 index 8fa3f0d6d..000000000 --- a/org.argeo.security.core/src/org/argeo/security/core/MatchingAuthenticationProvider.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.core; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -import org.springframework.core.io.Resource; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.GrantedAuthorityImpl; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; - -/** @deprecated */ -@Deprecated -public class MatchingAuthenticationProvider extends - AbstractUserDetailsAuthenticationProvider { - - private Resource mapping; - private Properties properties; - - private List defaultRoles = new ArrayList(); - - @Override - protected void doAfterPropertiesSet() throws Exception { - properties = new Properties(); - InputStream propIn = mapping.getInputStream(); - try { - properties.load(propIn); - } finally { - propIn.close(); - } - } - - @Override - protected void additionalAuthenticationChecks(UserDetails userDetails, - UsernamePasswordAuthenticationToken authentication) - throws AuthenticationException { - if (!userDetails.getPassword().equals(authentication.getCredentials())) - throw new BadCredentialsException( - "Invalid credentails provided by " - + authentication.getName()); - } - - @Override - protected UserDetails retrieveUser(String username, - UsernamePasswordAuthenticationToken authentication) - throws AuthenticationException { - String value = properties.getProperty(username); - if (value == null) - throw new BadCredentialsException("User " + username - + " is not registered"); - List grantedAuthorities = new ArrayList(); - for (String role : defaultRoles) - grantedAuthorities.add(new GrantedAuthorityImpl(role)); - return new User(username, value, true, true, true, true, - grantedAuthorities); - } - - public void setMapping(Resource mapping) { - this.mapping = mapping; - } - - public void setDefaultRoles(List defaultRoles) { - this.defaultRoles = defaultRoles; - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/core/OsAuthenticationProvider.java b/org.argeo.security.core/src/org/argeo/security/core/OsAuthenticationProvider.java deleted file mode 100644 index 4f1d56447..000000000 --- a/org.argeo.security.core/src/org/argeo/security/core/OsAuthenticationProvider.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.core; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.argeo.security.OsAuthenticationToken; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - -/** - * Validates an OS authentication. The id is that it will always be - * authenticated since we are always runnign within an OS, but the fact that the - * {@link Authentication} works properly depends on the proper OS login module - * having been called as well. TODO make it more configurable (base roles, is - * admin) - */ -public class OsAuthenticationProvider implements AuthenticationProvider { - final static String osUserRole = "ROLE_OS_USER"; - final static String userRole = "ROLE_USER"; - final static String adminRole = "ROLE_ADMIN"; - - final static Boolean isAdmin = true; - - public Authentication authenticate(Authentication authentication) - throws AuthenticationException { - return new OsAuthenticationToken(getBaseAuthorities()); - } - - public static Collection getBaseAuthorities() { - List auths = new ArrayList(); - auths.add(new SimpleGrantedAuthority(osUserRole)); - auths.add(new SimpleGrantedAuthority(userRole)); - if (isAdmin) - auths.add(new SimpleGrantedAuthority(adminRole)); - return auths; - } - - @SuppressWarnings("rawtypes") - public boolean supports(Class authentication) { - return OsAuthenticationToken.class.isAssignableFrom(authentication); - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/jcr/JcrUserDetails.java b/org.argeo.security.core/src/org/argeo/security/jcr/JcrUserDetails.java deleted file mode 100644 index 208f85261..000000000 --- a/org.argeo.security.core/src/org/argeo/security/jcr/JcrUserDetails.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.jcr; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.Property; -import javax.jcr.RepositoryException; -import javax.jcr.Session; - -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.UserJcrUtils; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.DisabledException; -import org.springframework.security.authentication.LockedException; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; - -/** User details based on a user profile node. */ -public class JcrUserDetails extends User implements ArgeoNames { - private static final long serialVersionUID = -8142764995842559646L; - private final String homePath; - private final String securityWorkspace; - - /** Human readable user name */ - private String displayName; - - protected JcrUserDetails(String securityWorkspace, String homePath, - String username, String password, boolean enabled, - boolean accountNonExpired, boolean credentialsNonExpired, - boolean accountNonLocked, - Collection authorities) - throws IllegalArgumentException { - super(username, password, enabled, accountNonExpired, - credentialsNonExpired, accountNonLocked, authorities); - this.homePath = homePath; - this.securityWorkspace = securityWorkspace; - } - - public JcrUserDetails(Node userProfile, String password, - Collection authorities) - throws RepositoryException { - super( - userProfile.getProperty(ARGEO_USER_ID).getString(), - password, - userProfile.getProperty(ARGEO_ENABLED).getBoolean(), - userProfile.getProperty(ARGEO_ACCOUNT_NON_EXPIRED).getBoolean(), - userProfile.getProperty(ARGEO_CREDENTIALS_NON_EXPIRED) - .getBoolean(), userProfile.getProperty( - ARGEO_ACCOUNT_NON_LOCKED).getBoolean(), authorities); - // human readable name - if (userProfile.hasProperty(Property.JCR_TITLE)) { - displayName = userProfile.getProperty(Property.JCR_TITLE) - .getString(); - if (displayName.trim().equals("")) - displayName = null; - } - if (displayName == null) - displayName = userProfile.getProperty(ARGEO_USER_ID).getString(); - // home is defined as the parent of the profile - homePath = userProfile.getParent().getPath(); - securityWorkspace = userProfile.getSession().getWorkspace().getName(); - } - - /** - * Convenience constructor - * - * @param session - * the security session - * @param username - * the username - * @param password - * the password, can be null - * @param authorities - * the granted authorities - */ - public JcrUserDetails(Session session, String username, String password, - Collection authorities) - throws RepositoryException { - this(UserJcrUtils.getUserProfile(session, username), - password != null ? password : "", authorities); - } - - /** - * Check the account status in JCR, throwing the exceptions expected by - * Spring security if needed. - */ - public static void checkAccountStatus(Node userProfile) { - try { - if (!userProfile.getProperty(ARGEO_ENABLED).getBoolean()) - throw new DisabledException(userProfile.getPath() - + " is disabled"); - if (!userProfile.getProperty(ARGEO_ACCOUNT_NON_LOCKED).getBoolean()) - throw new LockedException(userProfile.getPath() + " is locked"); - } catch (RepositoryException e) { - throw new BadCredentialsException("Cannot check account status", e); - } - } - - /** Clone immutable with new roles */ - public JcrUserDetails cloneWithNewRoles(List roles) { - List authorities = new ArrayList(); - for (String role : roles) { - authorities.add(new SimpleGrantedAuthority(role)); - } - return new JcrUserDetails(securityWorkspace, homePath, getUsername(), - getPassword(), isEnabled(), isAccountNonExpired(), - isAccountNonExpired(), isAccountNonLocked(), authorities); - } - - /** Clone immutable with new password */ - public JcrUserDetails cloneWithNewPassword(String password) { - return new JcrUserDetails(securityWorkspace, homePath, getUsername(), - password, isEnabled(), isAccountNonExpired(), - isAccountNonExpired(), isAccountNonLocked(), getAuthorities()); - } - - public String getHomePath() { - return homePath; - } - - /** Not yet API */ - public String getSecurityWorkspace() { - return securityWorkspace; - } - - /** The human readable name of this user */ - public String getDisplayName() { - return displayName; - } - - @Override - public String toString() { - return getDisplayName(); - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/jcr/NewUserDetails.java b/org.argeo.security.core/src/org/argeo/security/jcr/NewUserDetails.java deleted file mode 100644 index 2257e26fc..000000000 --- a/org.argeo.security.core/src/org/argeo/security/jcr/NewUserDetails.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.argeo.security.jcr; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import javax.jcr.Node; -import javax.jcr.RepositoryException; - -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; - -/** Used to create a new user */ -public class NewUserDetails extends User { - private static final long serialVersionUID = -8331941336984083297L; - - public NewUserDetails(String username, char[] password) { - this(username, password, null); - } - - public NewUserDetails(String username, char[] password, String[] roles) { - super(username, new String(password), false, false, false, false, - rolesToAuthorities(roles)); - } - - /** To be overriden */ - public void mapToProfileNode(Node userProfile) throws RepositoryException { - // does nothing by default - } - - private static Collection rolesToAuthorities( - String[] roles) { - List authorities = new ArrayList(); - if (roles != null) - for (String role : roles) { - authorities.add(new SimpleGrantedAuthority(role)); - } - return authorities; - } -} diff --git a/org.argeo.security.core/src/org/argeo/security/jcr/RemoteJcrRepositoryWrapper.java b/org.argeo.security.core/src/org/argeo/security/jcr/RemoteJcrRepositoryWrapper.java deleted file mode 100644 index 54406c0cb..000000000 --- a/org.argeo.security.core/src/org/argeo/security/jcr/RemoteJcrRepositoryWrapper.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.jcr; - -import javax.jcr.Credentials; -import javax.jcr.LoginException; -import javax.jcr.NoSuchWorkspaceException; -import javax.jcr.Repository; -import javax.jcr.RepositoryException; -import javax.jcr.RepositoryFactory; -import javax.jcr.Session; -import javax.jcr.SimpleCredentials; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.jcr.ArgeoJcrUtils; -import org.argeo.jcr.JcrRepositoryWrapper; -import org.argeo.security.NodeAuthenticationToken; -import org.argeo.security.SystemAuthentication; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; - -/** - * Wrapper around a remote Jackrabbit repository which allows to simplify - * configuration and intercept some actions. It exposes itself as a - * {@link Repository}. - */ -public class RemoteJcrRepositoryWrapper extends JcrRepositoryWrapper { - private final static Log log = LogFactory - .getLog(RemoteJcrRepositoryWrapper.class); - - private String uri = null; - - private RepositoryFactory repositoryFactory; - - // remote - private Credentials remoteSystemCredentials = null; - - /** - * Empty constructor, {@link #init()} should be called after properties have - * been set - */ - public RemoteJcrRepositoryWrapper() { - } - - /** - * Embedded constructor, calling the {@link #init()} method. - * - * @param alias - * if not null the repository will be published under this alias - */ - public RemoteJcrRepositoryWrapper(RepositoryFactory repositoryFactory, - String uri, Credentials remoteSystemCredentials) { - this.repositoryFactory = repositoryFactory; - this.uri = uri; - this.remoteSystemCredentials = remoteSystemCredentials; - init(); - } - - public void init() { - Repository repository = createJackrabbitRepository(); - setRepository(repository); - } - - /** Actually creates the new repository. */ - protected Repository createJackrabbitRepository() { - long begin = System.currentTimeMillis(); - try { - if (uri == null || uri.trim().equals("")) - throw new ArgeoException("Remote URI not set"); - - Repository repository = ArgeoJcrUtils.getRepositoryByUri( - repositoryFactory, uri); - if (repository == null) - throw new ArgeoException("Remote JCR repository " + uri - + " not found"); - double duration = ((double) (System.currentTimeMillis() - begin)) / 1000; - log.info("Created remote JCR repository in " + duration - + " s from URI " + uri); - // we assume that the data model of the remote repository has - // been properly initialized - return repository; - } catch (Exception e) { - throw new ArgeoException("Cannot create remote JCR repository " - + uri, e); - } - } - - /** Shutdown the repository */ - public void destroy() throws Exception { - super.destroy(); - } - - /** Central login method */ - public Session login(Credentials credentials, String workspaceName) - throws LoginException, NoSuchWorkspaceException, - RepositoryException { - - // retrieve credentials for remote - if (credentials == null) { - Authentication authentication = SecurityContextHolder.getContext() - .getAuthentication(); - if (authentication != null) { - if (authentication instanceof UsernamePasswordAuthenticationToken) { - UsernamePasswordAuthenticationToken upat = (UsernamePasswordAuthenticationToken) authentication; - credentials = new SimpleCredentials(upat.getName(), upat - .getCredentials().toString().toCharArray()); - } else if ((authentication instanceof SystemAuthentication) - || (authentication instanceof NodeAuthenticationToken)) { - credentials = remoteSystemCredentials; - } - } - } - - return super.login(credentials, workspaceName); - } - - public void setUri(String uri) { - this.uri = uri; - } - - public void setRepositoryFactory(RepositoryFactory repositoryFactory) { - this.repositoryFactory = repositoryFactory; - } - - public void setRemoteSystemCredentials(Credentials remoteSystemCredentials) { - this.remoteSystemCredentials = remoteSystemCredentials; - } - -} diff --git a/org.argeo.security.core/src/org/argeo/security/jcr/SecureThreadBoundSession.java b/org.argeo.security.core/src/org/argeo/security/jcr/SecureThreadBoundSession.java deleted file mode 100644 index e0e887a3e..000000000 --- a/org.argeo.security.core/src/org/argeo/security/jcr/SecureThreadBoundSession.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.jcr; - -import javax.jcr.Session; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.jcr.spring.ThreadBoundSession; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; - -/** - * Thread bounded JCR session factory which checks authentication and is - * autoconfigured in Spring. - */ -@Deprecated -public class SecureThreadBoundSession extends ThreadBoundSession { - private final static Log log = LogFactory - .getLog(SecureThreadBoundSession.class); - - @Override - protected Session preCall(Session session) { - Authentication authentication = SecurityContextHolder.getContext() - .getAuthentication(); - if (authentication != null) { - String userID = session.getUserID(); - String currentUserName = authentication.getName(); - if (currentUserName != null) { - if (!userID.equals(currentUserName)) { - log.warn("Current session has user ID " + userID - + " while logged is user is " + currentUserName - + "(authentication=" + authentication + ")" - + ". Re-login."); - // TODO throw an exception - return login(); - } - } - } - return super.preCall(session); - } - -} diff --git a/org.argeo.security.jackrabbit/src/org/argeo/security/jackrabbit/ArgeoLoginModule.java b/org.argeo.security.jackrabbit/src/org/argeo/security/jackrabbit/ArgeoLoginModule.java deleted file mode 100644 index c37ad0db3..000000000 --- a/org.argeo.security.jackrabbit/src/org/argeo/security/jackrabbit/ArgeoLoginModule.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.jackrabbit; - -import java.security.Principal; -import java.security.acl.Group; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; - -import javax.jcr.Credentials; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; - -import org.apache.jackrabbit.core.security.AnonymousPrincipal; -import org.apache.jackrabbit.core.security.authentication.AbstractLoginModule; -import org.apache.jackrabbit.core.security.authentication.Authentication; -import org.apache.jackrabbit.core.security.principal.AdminPrincipal; -import org.springframework.security.authentication.AnonymousAuthenticationToken; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.context.SecurityContextHolder; - -/** Jackrabbit login mechanism based on Spring Security */ -public class ArgeoLoginModule extends AbstractLoginModule { - private String adminRole = "ROLE_ADMIN"; - private String systemRole = "ROLE_SYSTEM"; - - /** - * Returns the Spring {@link org.springframework.security.Authentication} - * (which can be null) - */ - @Override - protected Principal getPrincipal(Credentials credentials) { - return SecurityContextHolder.getContext().getAuthentication(); - } - - protected Set getPrincipals() { - // use linked HashSet instead of HashSet in order to maintain the order - // of principals (as in the Subject). - org.springframework.security.core.Authentication authen = (org.springframework.security.core.Authentication) principal; - - Set principals = new LinkedHashSet(); - principals.add(authen); - - // if (authen instanceof SystemAuthentication) { - // principals.add(new AdminPrincipal(authen.getName())); - // // principals.add(new ArgeoSystemPrincipal(authen.getName())); - // } else - if (authen instanceof AnonymousAuthenticationToken) { - principals.add(new AnonymousPrincipal()); - } else { - for (GrantedAuthority ga : authen.getAuthorities()) { - if (ga instanceof Principal) - principals.add((Principal) ga); - // FIXME: make it more generic - String authority = ga.getAuthority(); - if (adminRole.equals(authority) || systemRole.equals(authority)) - principals.add(new AdminPrincipal(authen.getName())); - } - } - - // remove previous credentials - // Set thisCredentials = subject - // .getPublicCredentials(SimpleCredentials.class); - // if (thisCredentials != null) - // thisCredentials.clear(); - - return principals; - } - - /** - * Super implementation removes all {@link Principal}, the Spring - * {@link org.springframework.security.Authentication} as well. Here we - * simply clear Jackrabbit related {@link Principal}s. - */ - // @Override - // public boolean logout() throws LoginException { - // Set principals = subject.getPrincipals(); - // for (Principal principal : subject.getPrincipals()) { - // if ((principal instanceof AdminPrincipal) - // || (principal instanceof ArgeoSystemPrincipal) - // || (principal instanceof AnonymousPrincipal) - // || (principal instanceof GrantedAuthority)) { - // principals.remove(principal); - // } - // } - // // clearPrincipals(AdminPrincipal.class); - // // clearPrincipals(ArgeoSystemPrincipal.class); - // // clearPrincipals(AnonymousPrincipal.class); - // // clearPrincipals(GrantedAuthority.class); - // return true; - // } - - // private void clearPrincipals(Class clss) { - // Set principals = subject.getPrincipals(clss); - // if (principals != null) - // principals.clear(); - // } - - @SuppressWarnings("rawtypes") - @Override - protected void doInit(CallbackHandler callbackHandler, Session session, - Map options) throws LoginException { - } - - @Override - protected boolean impersonate(Principal principal, Credentials credentials) - throws RepositoryException, LoginException { - throw new UnsupportedOperationException( - "Impersonation is not yet supported"); - } - - @Override - protected Authentication getAuthentication(final Principal principal, - Credentials creds) throws RepositoryException { - if (principal instanceof Group) { - return null; - } - return new Authentication() { - public boolean canHandle(Credentials credentials) { - return principal instanceof org.springframework.security.core.Authentication; - } - - public boolean authenticate(Credentials credentials) - throws RepositoryException { - return ((org.springframework.security.core.Authentication) principal) - .isAuthenticated(); - } - }; - } - -} diff --git a/org.argeo.security.ui.admin/bnd.bnd b/org.argeo.security.ui.admin/bnd.bnd index 7d721beb0..6a128f699 100644 --- a/org.argeo.security.ui.admin/bnd.bnd +++ b/org.argeo.security.ui.admin/bnd.bnd @@ -12,6 +12,4 @@ org.eclipse.swt.widgets,\ org.eclipse.ui.services,\ org.osgi.framework,\ org.springframework.core,\ -org.springframework.dao,\ -org.springframework.security.provisioning,\ * diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/commands/NewUser.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/commands/NewUser.java index 838e66ff5..4c1e8f4cb 100644 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/commands/NewUser.java +++ b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/commands/NewUser.java @@ -26,7 +26,6 @@ import org.argeo.ArgeoException; import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.eclipse.ui.dialogs.ErrorFeedback; import org.argeo.jcr.ArgeoNames; -import org.argeo.security.UserAdminService; import org.argeo.security.ui.admin.SecurityAdminPlugin; import org.argeo.security.ui.admin.internal.UiAdminUtils; import org.argeo.security.ui.admin.internal.UserAdminConstants; @@ -53,6 +52,13 @@ import org.osgi.service.useradmin.UserAdminEvent; /** Open a wizard that enables creation of a new user. */ public class NewUser extends AbstractHandler { + /** + * Email addresses must match this regexp pattern ({@value #EMAIL_PATTERN}. + * Thanks to this tip. + */ + public final static String EMAIL_PATTERN = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; // private final static Log log = LogFactory.getLog(NewUser.class); public final static String ID = SecurityAdminPlugin.PLUGIN_ID + ".newUser"; @@ -239,8 +245,7 @@ public class NewUser extends AbstractHandler { .getRole(getDn(name)); if (role != null) return "User " + name + " already exists"; - if (!primaryMailTxt.getText().matches( - UserAdminService.EMAIL_PATTERN)) + if (!primaryMailTxt.getText().matches(EMAIL_PATTERN)) return "Not a valid email address"; if (lastNameTxt.getText().trim().equals("")) return "Specify a last name"; diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java deleted file mode 100644 index aa6e2c6be..000000000 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserBatchUpdateWizard.java +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.ui.admin.internal.parts; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jcr.Node; -import javax.jcr.NodeIterator; -import javax.jcr.RepositoryException; -import javax.jcr.Session; -import javax.jcr.version.VersionManager; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.ArgeoException; -import org.argeo.ArgeoMonitor; -import org.argeo.eclipse.ui.EclipseArgeoMonitor; -import org.argeo.eclipse.ui.parts.UsersTable; -import org.argeo.jcr.ArgeoNames; -import org.argeo.jcr.JcrUtils; -import org.argeo.security.UserAdminService; -import org.argeo.security.jcr.JcrUserDetails; -import org.argeo.security.ui.PrivilegedJob; -import org.argeo.security.ui.admin.SecurityAdminPlugin; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.jface.dialogs.IPageChangeProvider; -import org.eclipse.jface.dialogs.IPageChangedListener; -import org.eclipse.jface.dialogs.PageChangedEvent; -import org.eclipse.jface.wizard.IWizardContainer; -import org.eclipse.jface.wizard.Wizard; -import org.eclipse.jface.wizard.WizardPage; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -/** Wizard to update users */ -public class UserBatchUpdateWizard extends Wizard { - private final static Log log = LogFactory - .getLog(UserBatchUpdateWizard.class); - private Session session; - private UserAdminService userAdminService; - - // pages - private ChooseCommandWizardPage chooseCommandPage; - private ChooseUsersWizardPage userListPage; - private ValidateAndLaunchWizardPage validatePage; - - // ///////////////////////////////////////////////// - // / Definition of the various implemented commands - private final static String CMD_UPDATE_PASSWORD = "resetPassword"; - private final static String CMD_GROUP_MEMBERSHIP = "groupMembership"; - - private final Map commands = new HashMap() { - private static final long serialVersionUID = 1L; - { - put("Enable user(s)", ArgeoNames.ARGEO_ENABLED); - put("Expire credentials", ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED); - put("Expire account(s)", ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED); - put("Lock account(s)", ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED); - put("Reset password(s)", CMD_UPDATE_PASSWORD); - // TODO implement role / group management - // put("Add/Remove from group", CMD_GROUP_MEMBERSHIP); - } - }; - - public UserBatchUpdateWizard(Session session, - UserAdminService userAdminService) { - this.session = session; - this.userAdminService = userAdminService; - } - - @Override - public void addPages() { - chooseCommandPage = new ChooseCommandWizardPage(); - addPage(chooseCommandPage); - userListPage = new ChooseUsersWizardPage(session); - addPage(userListPage); - validatePage = new ValidateAndLaunchWizardPage(session); - addPage(validatePage); - } - - @Override - public boolean performFinish() { - if (!canFinish()) - return false; - - UpdateJob job = null; - if (ArgeoNames.ARGEO_ENABLED.equals(chooseCommandPage.getCommand())) { - job = new UpdateBoolean(session, userListPage.getSelectedUsers(), - ArgeoNames.ARGEO_ENABLED, - chooseCommandPage.getBoleanValue()); - } else if (ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED - .equals(chooseCommandPage.getCommand())) { - job = new UpdateBoolean(session, userListPage.getSelectedUsers(), - ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, - chooseCommandPage.getBoleanValue()); - } else if (ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED - .equals(chooseCommandPage.getCommand())) { - job = new UpdateBoolean(session, userListPage.getSelectedUsers(), - ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED, - chooseCommandPage.getBoleanValue()); - } else if (ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED.equals(chooseCommandPage - .getCommand())) { - job = new UpdateBoolean(session, userListPage.getSelectedUsers(), - ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED, - chooseCommandPage.getBoleanValue()); - } else if (CMD_UPDATE_PASSWORD.equals(chooseCommandPage.getCommand())) { - String newValue = chooseCommandPage.getPwdValue(); - if (newValue == null) - throw new ArgeoException( - "Password cannot be null or an empty string"); - job = new ResetPassword(session, userAdminService, - userListPage.getSelectedUsers(), newValue); - } - - if (job != null) - job.schedule(); - return true; - } - - public void setSession(Session session) { - this.session = session; - } - - public boolean canFinish() { - if (this.getContainer().getCurrentPage() == validatePage) - return true; - return false; - } - - // ///////////////////////// - // REEL UPDATE JOB - private class UpdateBoolean extends UpdateJob { - private String propertyName; - private boolean value; - - public UpdateBoolean(Session session, List nodesToUpdate, - String propertyName, boolean value) { - super(session, nodesToUpdate); - this.propertyName = propertyName; - this.value = value; - } - - protected void doUpdate(Node node) { - try { - node.setProperty(propertyName, value); - } catch (RepositoryException re) { - throw new ArgeoException( - "Unable to update boolean value for node " + node, re); - } - } - } - - private class ResetPassword extends UpdateJob { - private String newValue; - private UserAdminService userAdminService; - - public ResetPassword(Session session, - UserAdminService userAdminService, List nodesToUpdate, - String newValue) { - super(session, nodesToUpdate); - this.newValue = newValue; - this.userAdminService = userAdminService; - } - - protected void doUpdate(Node node) { - try { - String userId = node.getProperty(ArgeoNames.ARGEO_USER_ID) - .getString(); - if (userAdminService.userExists(userId)) { - JcrUserDetails userDetails = (JcrUserDetails) userAdminService - .loadUserByUsername(userId); - userAdminService.updateUser(userDetails - .cloneWithNewPassword(newValue)); - } - } catch (RepositoryException re) { - throw new ArgeoException( - "Unable to update boolean value for node " + node, re); - } - } - } - - @SuppressWarnings("unused") - private class AddToGroup extends UpdateJob { - private String groupID; - private Session session; - - public AddToGroup(Session session, List nodesToUpdate, - String groupID) { - super(session, nodesToUpdate); - this.session = session; - this.groupID = groupID; - } - - protected void doUpdate(Node node) { - log.info("Add/Remove to group actions are not yet implemented"); - // TODO implement this - // try { - // throw new ArgeoException("Not yet implemented"); - // } catch (RepositoryException re) { - // throw new ArgeoException( - // "Unable to update boolean value for node " + node, re); - // } - } - } - - /** - * Base privileged job that will be run asynchronously to perform the batch - * update - */ - private abstract class UpdateJob extends PrivilegedJob { - - private final Session currSession; - private final List nodesToUpdate; - - protected abstract void doUpdate(Node node); - - public UpdateJob(Session session, List nodesToUpdate) { - super("Perform update"); - try { - this.currSession = session.getRepository().login(); - // "move" nodes to update in the new session - // the "old" session will be closed by the calling command - // before the job has effectively ran - // TODO there must be a cleaner way to do. - List nodes = new ArrayList(); - for (Node node : nodesToUpdate) { - nodes.add(currSession.getNode(node.getPath())); - } - this.nodesToUpdate = nodes; - } catch (RepositoryException e) { - throw new ArgeoException("Error while dupplicating " - + "session for job", e); - } - } - - @Override - protected IStatus doRun(IProgressMonitor progressMonitor) { - try { - ArgeoMonitor monitor = new EclipseArgeoMonitor(progressMonitor); - VersionManager vm = currSession.getWorkspace() - .getVersionManager(); - int total = nodesToUpdate.size(); - monitor.beginTask("Performing change", total); - for (Node node : nodesToUpdate) { - String path = node.getPath(); - vm.checkout(path); - doUpdate(node); - currSession.save(); - vm.checkin(path); - monitor.worked(1); - } - } catch (Exception e) { - log.error("Cannot perform batch update on users", e); - // e.printStackTrace(); - - // Dig exception to find the root cause that will enable the - // user to understand the problem - Throwable cause = e; - Throwable originalCause = e; - while (cause != null) { - if (log.isTraceEnabled()) - log.trace("Parent Cause message : " - + cause.getMessage()); - originalCause = cause; - cause = cause.getCause(); - } - return new Status(IStatus.ERROR, SecurityAdminPlugin.PLUGIN_ID, - "Cannot perform updates.", originalCause); - } finally { - JcrUtils.logoutQuietly(currSession); - } - return Status.OK_STATUS; - } - } - - // ////////////////////// - // Pages definition - /** Displays a combo box that enables user to choose which action to perform */ - private class ChooseCommandWizardPage extends WizardPage { - private static final long serialVersionUID = 1L; - - private Combo chooseCommandCmb; - private Button trueChk; - private Text valueTxt; - private Text pwdTxt; - private Text pwd2Txt; - - public ChooseCommandWizardPage() { - super("Choose a command to run."); - setTitle("Choose a command to run."); - } - - @Override - public void createControl(Composite parent) { - GridLayout gl = new GridLayout(); - Composite container = new Composite(parent, SWT.NO_FOCUS); - container.setLayout(gl); - - chooseCommandCmb = new Combo(container, SWT.NO_FOCUS); - String[] values = commands.keySet().toArray( - new String[commands.size()]); - chooseCommandCmb.setItems(values); - chooseCommandCmb.setLayoutData(new GridData(SWT.FILL, SWT.TOP, - true, false)); - - final Composite bottomPart = new Composite(container, SWT.NO_FOCUS); - gl = new GridLayout(); - gl.horizontalSpacing = gl.marginWidth = gl.verticalSpacing = 0; - bottomPart.setLayout(gl); - bottomPart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, - true)); - - chooseCommandCmb.addSelectionListener(new SelectionListener() { - private static final long serialVersionUID = 1L; - - @Override - public void widgetSelected(SelectionEvent e) { - if (getCommand().equals(CMD_UPDATE_PASSWORD)) - populatePasswordCmp(bottomPart); - else if (getCommand().equals(CMD_GROUP_MEMBERSHIP)) - populateGroupCmp(bottomPart); - else - populateBooleanFlagCmp(bottomPart); - bottomPart.pack(true); - bottomPart.layout(); - } - - @Override - public void widgetDefaultSelected(SelectionEvent e) { - } - }); - - setControl(container); - } - - private void cleanParent(Composite parent) { - if (parent.getChildren().length > 0) { - for (Control control : parent.getChildren()) - control.dispose(); - } - } - - private void populateBooleanFlagCmp(Composite parent) { - cleanParent(parent); - trueChk = new Button(parent, SWT.CHECK); - trueChk.setText("Do it. (It will to the contrary if unchecked)"); - trueChk.setSelection(true); - trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); - } - - private void populatePasswordCmp(Composite parent) { - cleanParent(parent); - Composite body = new Composite(parent, SWT.NO_FOCUS); - body.setLayout(new GridLayout(2, false)); - body.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); - pwdTxt = createLP(body, "New password", ""); - pwd2Txt = createLP(body, "Repeat password", ""); - } - - /** Creates label and password. */ - protected Text createLP(Composite body, String label, String value) { - Label lbl = new Label(body, SWT.NONE); - lbl.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); - lbl.setText(label); - Text text = new Text(body, SWT.BORDER | SWT.PASSWORD); - text.setText(value); - text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - return text; - } - - private void populateGroupCmp(Composite parent) { - if (parent.getChildren().length > 0) { - for (Control control : parent.getChildren()) - control.dispose(); - } - trueChk = new Button(parent, SWT.CHECK); - trueChk.setText("Add to group. (It will remove user(s) from the " - + "corresponding group if unchecked)"); - trueChk.setSelection(true); - trueChk.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false)); - } - - protected String getCommand() { - return commands.get(chooseCommandCmb.getItem(chooseCommandCmb - .getSelectionIndex())); - } - - protected String getCommandLbl() { - return chooseCommandCmb.getItem(chooseCommandCmb - .getSelectionIndex()); - } - - protected boolean getBoleanValue() { - // FIXME this is not consistent and will lead to errors. - if (ArgeoNames.ARGEO_ENABLED.equals(getCommand())) - return trueChk.getSelection(); - else - return !trueChk.getSelection(); - } - - @SuppressWarnings("unused") - protected String getStringValue() { - String value = null; - if (valueTxt != null) { - value = valueTxt.getText(); - if ("".equals(value.trim())) - value = null; - } - return value; - } - - protected String getPwdValue() { - String newPwd = null; - if (pwdTxt == null || pwd2Txt == null) - return null; - if (!pwdTxt.getText().equals("") || !pwd2Txt.getText().equals("")) { - if (pwdTxt.getText().equals(pwd2Txt.getText())) { - newPwd = pwdTxt.getText(); - pwdTxt.setText(""); - pwd2Txt.setText(""); - } else { - pwdTxt.setText(""); - pwd2Txt.setText(""); - throw new ArgeoException("Passwords are not equals"); - } - } - return newPwd; - } - } - - /** - * Displays a list of users with a check box to be able to choose some of - * them - */ - private class ChooseUsersWizardPage extends WizardPage implements - IPageChangedListener { - private static final long serialVersionUID = 1L; - private UsersTable userTableCmp; - private Composite container; - private Session session; - - public ChooseUsersWizardPage(Session session) { - super("Choose Users"); - this.session = session; - setTitle("Select users who will be impacted"); - } - - @Override - public void createControl(Composite parent) { - container = new Composite(parent, SWT.NONE); - container.setLayout(new FillLayout()); - userTableCmp = new MyUserTableCmp(container, SWT.NO_FOCUS, session); - userTableCmp.populate(true, true); - setControl(container); - - // Add listener to update message when shown - final IWizardContainer container = this.getContainer(); - if (container instanceof IPageChangeProvider) { - ((IPageChangeProvider) container).addPageChangedListener(this); - } - - } - - @Override - public void pageChanged(PageChangedEvent event) { - if (event.getSelectedPage() == this) { - String msg = "Chosen batch action: " - + chooseCommandPage.getCommandLbl(); - ((WizardPage) event.getSelectedPage()).setMessage(msg); - } - } - - protected List getSelectedUsers() { - return userTableCmp.getSelectedUsers(); - } - - private class MyUserTableCmp extends UsersTable { - - private static final long serialVersionUID = 1L; - - public MyUserTableCmp(Composite parent, int style, Session session) { - super(parent, style, session); - } - - @Override - protected void refreshFilteredList() { - List nodes = new ArrayList(); - try { - NodeIterator ni = listFilteredElements(session, - getFilterString()); - - users: while (ni.hasNext()) { - Node currNode = ni.nextNode(); - String username = currNode.hasProperty(ARGEO_USER_ID) ? currNode - .getProperty(ARGEO_USER_ID).getString() : ""; - if (username.equals(session.getUserID())) - continue users; - else - nodes.add(currNode); - } - getTableViewer().setInput(nodes.toArray()); - } catch (RepositoryException e) { - throw new ArgeoException("Unable to list users", e); - } - } - } - } - - /** - * Recapitulation of input data before running real update - */ - private class ValidateAndLaunchWizardPage extends WizardPage implements - IPageChangedListener { - private static final long serialVersionUID = 1L; - private UsersTable userTableCmp; - private Session session; - - public ValidateAndLaunchWizardPage(Session session) { - super("Validate and launch"); - this.session = session; - setTitle("Validate and launch"); - } - - @Override - public void createControl(Composite parent) { - Composite mainCmp = new Composite(parent, SWT.NO_FOCUS); - mainCmp.setLayout(new FillLayout()); - - // Add listener to update user list when shown - final IWizardContainer container = this.getContainer(); - if (container instanceof IPageChangeProvider) { - ((IPageChangeProvider) container).addPageChangedListener(this); - } - - userTableCmp = new UsersTable(mainCmp, SWT.NO_FOCUS, session); - userTableCmp.populate(false, false); - setControl(mainCmp); - } - - @Override - public void pageChanged(PageChangedEvent event) { - if (event.getSelectedPage() == this) { - @SuppressWarnings({ "unchecked", "rawtypes" }) - Object[] values = ((ArrayList) userListPage.getSelectedUsers()) - .toArray(new Object[userListPage.getSelectedUsers() - .size()]); - userTableCmp.getTableViewer().setInput(values); - String msg = "Following batch action: [" - + chooseCommandPage.getCommandLbl() - + "] will be perfomed on the users listed below.\n" - + "Are you sure you want to proceed?"; - ((WizardPage) event.getSelectedPage()).setMessage(msg); - } - } - - // private class MyUserTableCmp extends UserTableComposite { - // public MyUserTableCmp(Composite parent, int style, Session session) { - // super(parent, style, session); - // } - // - // @Override - // protected void refreshFilteredList() { - // @SuppressWarnings({ "unchecked", "rawtypes" }) - // - // setFilteredList(values); - // } - // - // @Override - // public void setVisible(boolean visible) { - // super.setVisible(visible); - // if (visible) - // refreshFilteredList(); - // } - // } - } -} \ No newline at end of file diff --git a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserRolesPage.java b/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserRolesPage.java deleted file mode 100644 index 2b6ba6968..000000000 --- a/org.argeo.security.ui.admin/src/org/argeo/security/ui/admin/internal/parts/UserRolesPage.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2007-2012 Argeo GmbH - * - * 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 org.argeo.security.ui.admin.internal.parts; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.jcr.ArgeoNames; -import org.argeo.security.UserAdminService; -import org.argeo.security.ui.admin.SecurityAdminPlugin; -import org.eclipse.jface.viewers.CellEditor; -import org.eclipse.jface.viewers.CheckboxCellEditor; -import org.eclipse.jface.viewers.ColumnLabelProvider; -import org.eclipse.jface.viewers.EditingSupport; -import org.eclipse.jface.viewers.IStructuredContentProvider; -import org.eclipse.jface.viewers.TableViewer; -import org.eclipse.jface.viewers.TableViewerColumn; -import org.eclipse.jface.viewers.Viewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.FillLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; -import org.eclipse.ui.forms.AbstractFormPart; -import org.eclipse.ui.forms.IManagedForm; -import org.eclipse.ui.forms.editor.FormEditor; -import org.eclipse.ui.forms.editor.FormPage; -import org.eclipse.ui.forms.widgets.ScrolledForm; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -/** - * Display/edit the roles of a user. - */ -public class UserRolesPage extends FormPage implements ArgeoNames { - final static String ID = "argeoUserEditor.rolesPage"; - - private final static Log log = LogFactory.getLog(UserRolesPage.class); - private final static Image ROLE_CHECKED = SecurityAdminPlugin - .getImageDescriptor("icons/security.gif").createImage(); - - private TableViewer rolesViewer; - private UserAdminService userAdminService; - private List roles; - - public UserRolesPage(FormEditor editor, UserDetails userDetails, - UserAdminService userAdminService) { - super(editor, ID, "Roles"); - setUserDetails(userDetails); - this.userAdminService = userAdminService; - } - - public void setUserDetails(UserDetails userDetails) { - this.roles = new ArrayList(); - for (GrantedAuthority ga : userDetails.getAuthorities()) - roles.add(ga.getAuthority()); - if (rolesViewer != null) - rolesViewer.refresh(); - } - - protected void createFormContent(final IManagedForm mf) { - ScrolledForm form = mf.getForm(); - form.setText("Roles"); - FillLayout mainLayout = new FillLayout(); - // ColumnLayout mainLayout = new ColumnLayout(); - // mainLayout.minNumColumns = 1; - // mainLayout.maxNumColumns = 4; - // mainLayout.topMargin = 0; - // mainLayout.bottomMargin = 5; - // mainLayout.leftMargin = mainLayout.rightMargin = - // mainLayout.horizontalSpacing = mainLayout.verticalSpacing = 10; - form.getBody().setLayout(mainLayout); - createRolesPart(form.getBody()); - } - - /** Creates the role section */ - protected void createRolesPart(Composite parent) { - Table table = new Table(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); - - AbstractFormPart part = new AbstractFormPart() { - public void commit(boolean onSave) { - // roles have already been modified in editing - super.commit(onSave); - if (log.isTraceEnabled()) - log.trace("Role part committed"); - } - }; - getManagedForm().addPart(part); - - // GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true); - // gridData.verticalSpan = 20; - // table.setLayoutData(gridData); - table.setLinesVisible(true); - table.setHeaderVisible(false); - rolesViewer = new TableViewer(table); - - // check column - TableViewerColumn column = createTableViewerColumn(rolesViewer, - "checked", 20); - column.setLabelProvider(new ColumnLabelProvider() { - private static final long serialVersionUID = -1354458151271666525L; - - public String getText(Object element) { - return null; - } - - public Image getImage(Object element) { - String role = element.toString(); - if (roles.contains(role)) { - return ROLE_CHECKED; - } else { - return null; - } - } - }); - column.setEditingSupport(new RoleEditingSupport(rolesViewer, part)); - - // role column - column = createTableViewerColumn(rolesViewer, "Role", 200); - column.setLabelProvider(new ColumnLabelProvider() { - private static final long serialVersionUID = 2968056181744306838L; - - public String getText(Object element) { - return element.toString(); - } - - public Image getImage(Object element) { - return null; - } - }); - rolesViewer.setContentProvider(new RolesContentProvider()); - rolesViewer.setInput(getEditorSite()); - } - - protected TableViewerColumn createTableViewerColumn(TableViewer viewer, - String title, int bound) { - final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, - SWT.NONE); - final TableColumn column = viewerColumn.getColumn(); - column.setText(title); - column.setWidth(bound); - column.setResizable(true); - column.setMoveable(true); - return viewerColumn; - - } - - public List getRoles() { - return roles; - } - - public void refresh() { - rolesViewer.refresh(); - } - - private class RolesContentProvider implements IStructuredContentProvider { - private static final long serialVersionUID = -1882254608698512781L; - - public Object[] getElements(Object inputElement) { - return userAdminService.listEditableRoles().toArray(); - } - - public void dispose() { - } - - public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - } - } - - /** Select the columns by editing the checkbox in the first column */ - class RoleEditingSupport extends EditingSupport { - private static final long serialVersionUID = 4041402007711754376L; - private final TableViewer viewer; - private final AbstractFormPart formPart; - - public RoleEditingSupport(TableViewer viewer, AbstractFormPart formPart) { - super(viewer); - this.viewer = viewer; - this.formPart = formPart; - } - - @Override - protected CellEditor getCellEditor(Object element) { - return new CheckboxCellEditor(null, SWT.CHECK | SWT.READ_ONLY); - - } - - @Override - protected boolean canEdit(Object element) { - return true; - } - - @Override - protected Object getValue(Object element) { - String role = element.toString(); - return roles.contains(role); - - } - - @Override - protected void setValue(Object element, Object value) { - Boolean inRole = (Boolean) value; - String role = element.toString(); - if (inRole && !roles.contains(role)) { - roles.add(role); - formPart.markDirty(); - } else if (!inRole && roles.contains(role)) { - roles.remove(role); - formPart.markDirty(); - } - viewer.refresh(); - } - } - -} diff --git a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java index eec4d0bd0..c27fbc70e 100644 --- a/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java +++ b/org.argeo.security.ui.rap/src/org/argeo/security/ui/rap/SecureEntryPoint.java @@ -23,7 +23,7 @@ import java.security.PrivilegedAction; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.CredentialNotFoundException; +import javax.security.auth.login.FailedLoginException; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.security.auth.x500.X500Principal; @@ -43,7 +43,6 @@ import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.application.EntryPoint; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; -import org.springframework.security.authentication.BadCredentialsException; /** * RAP entry point with login capabilities. Once the user has been @@ -117,14 +116,12 @@ public class SecureEntryPoint implements EntryPoint { if (log.isDebugEnabled()) log.debug("Authenticated " + subject); + } catch (FailedLoginException e) { + MessageDialog.openInformation(display.getActiveShell(), + "Bad Credentials", e.getMessage()); + // retry login + continue tryLogin; } catch (LoginException e) { - BadCredentialsException bce = wasCausedByBadCredentials(e); - if (bce != null) { - MessageDialog.openInformation(display.getActiveShell(), - "Bad Credentials", bce.getMessage()); - // retry login - continue tryLogin; - } return processLoginDeath(display, e); } } @@ -192,20 +189,6 @@ public class SecureEntryPoint implements EntryPoint { } - /** Recursively look for {@link BadCredentialsException} in the root causes. */ - private BadCredentialsException wasCausedByBadCredentials(Throwable t) { - if (t instanceof BadCredentialsException) - return (BadCredentialsException) t; - - if (t instanceof CredentialNotFoundException) - return new BadCredentialsException("Login canceled"); - - if (t.getCause() != null) - return wasCausedByBadCredentials(t.getCause()); - else - return null; - } - /** * If there is a {@link ThreadDeath} in the root causes, rethrow it * (important for RAP cleaning mechanism) diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/PrivilegedJob.java b/org.argeo.security.ui/src/org/argeo/security/ui/PrivilegedJob.java index 33ee4a6c9..3a9ade427 100644 --- a/org.argeo.security.ui/src/org/argeo/security/ui/PrivilegedJob.java +++ b/org.argeo.security.ui/src/org/argeo/security/ui/PrivilegedJob.java @@ -1,5 +1,6 @@ package org.argeo.security.ui; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; @@ -8,22 +9,22 @@ import javax.security.auth.Subject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.jobs.Job; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; /** * Propagate authentication to an eclipse job. Typically to execute a privileged * action outside the UI thread */ public abstract class PrivilegedJob extends Job { - - private final Authentication authentication; - private Subject subject; + private final Subject subject; public PrivilegedJob(String jobName) { + this(jobName, AccessController.getContext()); + } + + public PrivilegedJob(String jobName, + AccessControlContext accessControlContext) { super(jobName); - authentication = SecurityContextHolder.getContext().getAuthentication(); - subject = Subject.getSubject(AccessController.getContext()); + subject = Subject.getSubject(accessControlContext); // Must be called *before* the job is scheduled, // it is required for the progress window to appear @@ -34,8 +35,6 @@ public abstract class PrivilegedJob extends Job { protected IStatus run(final IProgressMonitor progressMonitor) { PrivilegedAction privilegedAction = new PrivilegedAction() { public IStatus run() { - SecurityContextHolder.getContext().setAuthentication( - authentication); return doRun(progressMonitor); } }; diff --git a/org.argeo.security.ui/src/org/argeo/security/ui/internal/CurrentUser.java b/org.argeo.security.ui/src/org/argeo/security/ui/internal/CurrentUser.java index f5a242d3a..73932a7a4 100644 --- a/org.argeo.security.ui/src/org/argeo/security/ui/internal/CurrentUser.java +++ b/org.argeo.security.ui/src/org/argeo/security/ui/internal/CurrentUser.java @@ -15,17 +15,9 @@ */ package org.argeo.security.ui.internal; -import java.security.AccessController; -import java.security.Principal; -import java.security.acl.Group; -import java.util.Collections; -import java.util.HashSet; import java.util.Set; -import javax.security.auth.Subject; -import javax.security.auth.x500.X500Principal; - -import org.argeo.ArgeoException; +import org.argeo.security.SecurityUtils; /** * Retrieves information about the current user. Not an API, can change without @@ -33,60 +25,10 @@ import org.argeo.ArgeoException; */ public class CurrentUser { public final static String getUsername() { - Subject subject = getSubject(); - if (subject == null) - return null; - Principal principal = subject.getPrincipals(X500Principal.class) - .iterator().next(); - return principal.getName(); - + return SecurityUtils.getUsername(); } public final static Set roles() { - Set roles = Collections.synchronizedSet(new HashSet()); - // roles.add("ROLE_USER"); - Subject subject = getSubject(); - X500Principal userPrincipal = subject - .getPrincipals(X500Principal.class).iterator().next(); - roles.add(userPrincipal.getName()); - for (Principal group : subject.getPrincipals(Group.class)) { - roles.add(group.getName()); - } - return roles; - } - - // public final static String getUsername() { - // return getAuthentication().getName(); - // } - - // public final static Set roles() { - // Set roles = Collections.synchronizedSet(new HashSet()); - // Authentication authentication = getAuthentication(); - // for (GrantedAuthority ga : authentication.getAuthorities()) { - // roles.add(ga.getAuthority()); - // } - // return Collections.unmodifiableSet(roles); - // } - // - // public final static Authentication getAuthentication() { - // return SecurityContextHolder.getContext().getAuthentication(); - // } - - // public final static Authentication getAuthentication() { - // Set authens = getSubject().getPrincipals( - // Authentication.class); - // if (authens != null && !authens.isEmpty()) { - // Principal principal = authens.iterator().next(); - // Authentication authentication = (Authentication) principal; - // return authentication; - // } - // throw new ArgeoException("No authentication found"); - // } - - public final static Subject getSubject() { - Subject subject = Subject.getSubject(AccessController.getContext()); - if (subject == null) - throw new ArgeoException("Not authenticated."); - return subject; + return SecurityUtils.roles(); } } diff --git a/pom.xml b/pom.xml index d0b8219f6..7e7ad7591 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.argeo.commons argeo-commons @@ -398,6 +399,36 @@ limitations under the License. argeo-tp ${version.argeo-distribution} provided + + + org.argeo.tp.spring + org.springframework.ldap + + + org.argeo.tp.spring.security + org.springframework.security.acls + + + org.argeo.tp.spring.security + org.springframework.security.aspects + + + org.argeo.tp.spring.security + org.springframework.security.config + + + org.argeo.tp.spring.security + org.springframework.security.core + + + org.argeo.tp.spring.security + org.springframework.security.ldap + + + org.argeo.tp.spring.security + org.springframework.security.web + + -- 2.30.2