[SYNCOPE-652] Now account lockout is working properly again
Project: http://git-wip-us.apache.org/repos/asf/syncope/repo Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/5cf6aae8 Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/5cf6aae8 Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/5cf6aae8 Branch: refs/heads/SYNCOPE-156 Commit: 5cf6aae8274d8e10b884ec9faeca54f623234836 Parents: 6dfedd8 Author: Francesco Chicchiriccò <[email protected]> Authored: Tue Aug 11 08:18:54 2015 +0200 Committer: Francesco Chicchiriccò <[email protected]> Committed: Thu Aug 13 17:16:51 2015 +0200 ---------------------------------------------------------------------- .../client/console/rest/UserRestClient.java | 6 +- .../syncope/common/lib/mod/StatusMod.java | 2 + .../common/rest/api/service/UserService.java | 2 +- .../core/misc/security/AuthDataAccessor.java | 282 +++++++++++++++++++ .../security/SyncopeAuthenticationProvider.java | 276 +++++++----------- .../security/SyncopeUserDetailsService.java | 88 +----- .../misc/src/main/resources/securityContext.xml | 2 + .../core/persistence/api/dao/UserDAO.java | 3 + .../core/persistence/jpa/dao/JPADomainDAO.java | 2 + .../core/persistence/jpa/dao/JPAUserDAO.java | 21 +- .../api/UserProvisioningManager.java | 3 +- .../core/provisioning/api/UserSuspender.java | 26 -- .../java/DefaultUserProvisioningManager.java | 13 +- .../provisioning/java/UserSuspenderImpl.java | 51 ---- .../java/data/UserDataBinderImpl.java | 2 +- .../core/rest/cxf/service/UserServiceImpl.java | 5 +- .../activiti/ActivitiUserWorkflowAdapter.java | 15 +- .../core/workflow/api/UserWorkflowAdapter.java | 9 +- .../java/AbstractUserWorkflowAdapter.java | 54 +++- .../camel/AbstractCamelProvisioningManager.java | 4 +- .../camel/CamelUserProvisioningManager.java | 10 +- .../processor/UserInnerSuspendProcessor.java | 61 ---- .../processor/UserInternalSuspendProcessor.java | 61 ++++ .../src/main/resources/userRoutes.xml | 12 +- .../core/reference/AuthenticationITCase.java | 5 +- .../syncope/fit/core/reference/UserITCase.java | 33 ++- .../fit/core/reference/VirAttrITCase.java | 6 +- pom.xml | 2 +- 28 files changed, 559 insertions(+), 497 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java ---------------------------------------------------------------------- diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java index 5c5c062..d161658 100644 --- a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java +++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserRestClient.java @@ -124,20 +124,22 @@ public class UserRestClient extends AbstractAnyRestClient { public void suspend(final String etag, final long userKey, final List<StatusBean> statuses) { StatusMod statusMod = StatusUtils.buildStatusMod(statuses, false); + statusMod.setKey(userKey); statusMod.setType(StatusMod.ModType.SUSPEND); synchronized (this) { UserService service = getService(etag, UserService.class); - service.status(userKey, statusMod); + service.status(statusMod); resetClient(UserService.class); } } public void reactivate(final String etag, final long userKey, final List<StatusBean> statuses) { StatusMod statusMod = StatusUtils.buildStatusMod(statuses, true); + statusMod.setKey(userKey); statusMod.setType(StatusMod.ModType.REACTIVATE); synchronized (this) { UserService service = getService(etag, UserService.class); - service.status(userKey, statusMod); + service.status(statusMod); resetClient(UserService.class); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java ---------------------------------------------------------------------- diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java index 082b6f8..f989ecf 100644 --- a/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java +++ b/common/lib/src/main/java/org/apache/syncope/common/lib/mod/StatusMod.java @@ -21,6 +21,7 @@ package org.apache.syncope.common.lib.mod; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; import java.util.List; +import javax.ws.rs.PathParam; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlEnum; @@ -66,6 +67,7 @@ public class StatusMod extends AbstractBaseBean { */ private final List<String> resourceNames = new ArrayList<>(); + @PathParam("key") public long getKey() { return key; } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java ---------------------------------------------------------------------- diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java index bf1e6b7..6dbb56c 100644 --- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java +++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserService.java @@ -107,5 +107,5 @@ public interface UserService extends AnyService<UserTO, UserMod> { @Path("{key}/status") @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON }) - Response status(@NotNull @PathParam("key") Long key, @NotNull StatusMod statusMod); + Response status(@NotNull StatusMod statusMod); } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java ---------------------------------------------------------------------- diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java new file mode 100644 index 0000000..7643f9d --- /dev/null +++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/AuthDataAccessor.java @@ -0,0 +1,282 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.syncope.core.misc.security; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import javax.annotation.Resource; +import org.apache.commons.collections4.Closure; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.IteratorUtils; +import org.apache.commons.collections4.PredicateUtils; +import org.apache.commons.collections4.SetUtils; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.syncope.common.lib.SyncopeConstants; +import org.apache.syncope.common.lib.types.AuditElements; +import org.apache.syncope.common.lib.types.Entitlement; +import org.apache.syncope.core.misc.AuditManager; +import org.apache.syncope.core.misc.MappingUtils; +import org.apache.syncope.core.misc.RealmUtils; +import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO; +import org.apache.syncope.core.persistence.api.dao.ConfDAO; +import org.apache.syncope.core.persistence.api.dao.DomainDAO; +import org.apache.syncope.core.persistence.api.dao.GroupDAO; +import org.apache.syncope.core.persistence.api.dao.NotFoundException; +import org.apache.syncope.core.persistence.api.dao.RealmDAO; +import org.apache.syncope.core.persistence.api.dao.UserDAO; +import org.apache.syncope.core.persistence.api.entity.Domain; +import org.apache.syncope.core.persistence.api.entity.Realm; +import org.apache.syncope.core.persistence.api.entity.Role; +import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr; +import org.apache.syncope.core.persistence.api.entity.group.Group; +import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; +import org.apache.syncope.core.persistence.api.entity.user.User; +import org.apache.syncope.core.provisioning.api.ConnectorFactory; +import org.identityconnectors.framework.common.objects.Uid; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.DisabledException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.transaction.annotation.Transactional; + +public class AuthDataAccessor { + + protected static final Logger LOG = LoggerFactory.getLogger(AuthDataAccessor.class); + + @Resource(name = "adminUser") + protected String adminUser; + + @Resource(name = "anonymousUser") + protected String anonymousUser; + + @Autowired + protected DomainDAO domainDAO; + + @Autowired + protected ConfDAO confDAO; + + @Autowired + protected RealmDAO realmDAO; + + @Autowired + protected UserDAO userDAO; + + @Autowired + protected GroupDAO groupDAO; + + @Autowired + protected AnyTypeDAO anyTypeDAO; + + @Autowired + protected ConnectorFactory connFactory; + + @Autowired + protected AuditManager auditManager; + + protected final Encryptor encryptor = Encryptor.getInstance(); + + @Transactional(readOnly = true) + public Domain findDomain(final String key) { + Domain domain = domainDAO.find(key); + if (domain == null) { + throw new NotFoundException("Could not find domain " + key); + } + return domain; + } + + @Transactional(noRollbackFor = DisabledException.class) + public Pair<Long, Boolean> authenticate(final Authentication authentication) { + Long key = null; + Boolean authenticated = false; + + User user = userDAO.find(authentication.getName()); + if (user != null) { + key = user.getKey(); + + if (user.isSuspended() != null && user.isSuspended()) { + throw new DisabledException("User " + user.getUsername() + " is suspended"); + } + + CPlainAttr authStatuses = confDAO.find("authentication.statuses"); + if (authStatuses != null && !authStatuses.getValuesAsStrings().contains(user.getStatus())) { + throw new DisabledException("User " + user.getUsername() + " not allowed to authenticate"); + } + + boolean userModified = false; + authenticated = authenticate(user, authentication.getCredentials().toString()); + if (authenticated) { + if (confDAO.find("log.lastlogindate", Boolean.toString(true)).getValues().get(0).getBooleanValue()) { + user.setLastLoginDate(new Date()); + userModified = true; + } + + if (user.getFailedLogins() != 0) { + user.setFailedLogins(0); + userModified = true; + } + + } else { + user.setFailedLogins(user.getFailedLogins() + 1); + userModified = true; + } + + if (userModified) { + userDAO.save(user); + } + } + + return ImmutablePair.of(key, authenticated); + } + + protected boolean authenticate(final User user, final String password) { + boolean authenticated = encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword()); + LOG.debug("{} authenticated on internal storage: {}", user.getUsername(), authenticated); + + for (Iterator<? extends ExternalResource> itor = getPassthroughResources(user).iterator(); + itor.hasNext() && !authenticated;) { + + ExternalResource resource = itor.next(); + String connObjectKey = null; + try { + connObjectKey = MappingUtils.getConnObjectKeyValue(user, resource.getProvision(anyTypeDAO.findUser())); + Uid uid = connFactory.getConnector(resource).authenticate(connObjectKey, password, null); + if (uid != null) { + authenticated = true; + } + } catch (Exception e) { + LOG.debug("Could not authenticate {} on {}", user.getUsername(), resource.getKey(), e); + } + LOG.debug("{} authenticated on {} as {}: {}", + user.getUsername(), resource.getKey(), connObjectKey, authenticated); + } + + return authenticated; + } + + protected Set<? extends ExternalResource> getPassthroughResources(final User user) { + Set<? extends ExternalResource> result = null; + + // 1. look for assigned resources, pick the ones whose account policy has authentication resources + for (ExternalResource resource : userDAO.findAllResources(user)) { + if (resource.getAccountPolicy() != null && !resource.getAccountPolicy().getResources().isEmpty()) { + if (result == null) { + result = resource.getAccountPolicy().getResources(); + } else { + result.retainAll(resource.getAccountPolicy().getResources()); + } + } + } + + // 2. look for realms, pick the ones whose account policy has authentication resources + for (Realm realm : realmDAO.findAncestors(user.getRealm())) { + if (realm.getAccountPolicy() != null && !realm.getAccountPolicy().getResources().isEmpty()) { + if (result == null) { + result = realm.getAccountPolicy().getResources(); + } else { + result.retainAll(realm.getAccountPolicy().getResources()); + } + } + } + + return SetUtils.emptyIfNull(result); + } + + @Transactional(readOnly = true) + public void audit( + final AuditElements.EventCategoryType type, + final String category, + final String subcategory, + final String event, + final AuditElements.Result result, + final Object before, + final Object output, + final Object... input) { + + auditManager.audit(type, category, subcategory, event, result, before, output, input); + } + + @Transactional + public Set<SyncopeGrantedAuthority> load(final String username) { + final Set<SyncopeGrantedAuthority> authorities = new HashSet<>(); + if (anonymousUser.equals(username)) { + authorities.add(new SyncopeGrantedAuthority(Entitlement.ANONYMOUS)); + } else if (adminUser.equals(username)) { + CollectionUtils.collect(IteratorUtils.filteredIterator(Entitlement.values().iterator(), + PredicateUtils.notPredicate(PredicateUtils.equalPredicate(Entitlement.ANONYMOUS))), + new Transformer<String, SyncopeGrantedAuthority>() { + + @Override + public SyncopeGrantedAuthority transform(final String entitlement) { + return new SyncopeGrantedAuthority(entitlement, SyncopeConstants.ROOT_REALM); + } + }, + authorities); + } else { + User user = userDAO.find(username); + if (user == null) { + throw new UsernameNotFoundException("Could not find any user with id " + username); + } + + // Give entitlements as assigned by roles (with realms, where applicable) - assigned either + // statically and dynamically + for (final Role role : userDAO.findAllRoles(user)) { + CollectionUtils.forAllDo(role.getEntitlements(), new Closure<String>() { + + @Override + public void execute(final String entitlement) { + SyncopeGrantedAuthority authority = new SyncopeGrantedAuthority(entitlement); + authorities.add(authority); + + List<String> realmFullPahs = new ArrayList<>(); + CollectionUtils.collect(role.getRealms(), new Transformer<Realm, String>() { + + @Override + public String transform(final Realm realm) { + return realm.getFullPath(); + } + }, realmFullPahs); + authority.addRealms(realmFullPahs); + } + }); + } + + // Give group entitlements for owned groups + for (Group group : groupDAO.findOwnedByUser(user.getKey())) { + for (String entitlement : Arrays.asList( + Entitlement.GROUP_READ, Entitlement.GROUP_UPDATE, Entitlement.GROUP_DELETE)) { + + SyncopeGrantedAuthority authority = new SyncopeGrantedAuthority(entitlement); + authority.addRealm(RealmUtils.getGroupOwnerRealm(group.getRealm().getFullPath(), group.getKey())); + authorities.add(authority); + } + } + } + + return authorities; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java ---------------------------------------------------------------------- diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java index f452128..c8fa53d 100644 --- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java +++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeAuthenticationProvider.java @@ -18,44 +18,26 @@ */ package org.apache.syncope.core.misc.security; -import java.util.Date; -import java.util.Iterator; -import java.util.Set; import javax.annotation.Resource; -import org.apache.commons.collections4.SetUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.common.lib.SyncopeConstants; import org.apache.syncope.common.lib.types.AuditElements; import org.apache.syncope.common.lib.types.AuditElements.Result; import org.apache.syncope.common.lib.types.CipherAlgorithm; -import org.apache.syncope.core.persistence.api.dao.ConfDAO; -import org.apache.syncope.core.persistence.api.dao.PolicyDAO; -import org.apache.syncope.core.persistence.api.dao.UserDAO; -import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory; -import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; -import org.apache.syncope.core.persistence.api.entity.conf.CPlainAttr; -import org.apache.syncope.core.persistence.api.entity.user.User; -import org.apache.syncope.core.provisioning.api.ConnectorFactory; -import org.apache.syncope.core.misc.AuditManager; -import org.apache.syncope.core.misc.MappingUtils; -import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO; -import org.apache.syncope.core.persistence.api.dao.DomainDAO; -import org.apache.syncope.core.persistence.api.dao.NotFoundException; -import org.apache.syncope.core.persistence.api.dao.RealmDAO; import org.apache.syncope.core.persistence.api.entity.Domain; -import org.apache.syncope.core.persistence.api.entity.Realm; -import org.identityconnectors.framework.common.objects.Uid; +import org.apache.syncope.core.provisioning.api.UserProvisioningManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.DisabledException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.transaction.annotation.Transactional; @Configurable public class SyncopeAuthenticationProvider implements AuthenticationProvider { @@ -63,31 +45,10 @@ public class SyncopeAuthenticationProvider implements AuthenticationProvider { protected static final Logger LOG = LoggerFactory.getLogger(SyncopeAuthenticationProvider.class); @Autowired - protected AuditManager auditManager; + protected AuthDataAccessor dataAccessor; @Autowired - protected DomainDAO domainDAO; - - @Autowired - protected ConfDAO confDAO; - - @Autowired - protected RealmDAO realmDAO; - - @Autowired - protected UserDAO userDAO; - - @Autowired - protected PolicyDAO policyDAO; - - @Autowired - protected AnyTypeDAO anyTypeDAO; - - @Autowired - protected ConnectorFactory connFactory; - - @Autowired - protected AnyUtilsFactory attrUtilsFactory; + protected UserProvisioningManager provisioningManager; @Resource(name = "adminUser") protected String adminUser; @@ -130,19 +91,26 @@ public class SyncopeAuthenticationProvider implements AuthenticationProvider { this.userDetailsService = syncopeUserDetailsService; } + protected <T> T execWithAuthContext(final String domainKey, final Executable<T> executable) { + SecurityContext ctx = SecurityContextHolder.getContext(); + AuthContextUtils.setFakeAuth(domainKey); + try { + return executable.exec(); + } finally { + AuthContextUtils.clearFakeAuth(); + SecurityContextHolder.setContext(ctx); + } + } + @Override - @Transactional(noRollbackFor = { BadCredentialsException.class, DisabledException.class }) public Authentication authenticate(final Authentication authentication) { - boolean authenticated = false; - - String domainKey = authentication.getDetails() instanceof SyncopeAuthenticationDetails - ? SyncopeAuthenticationDetails.class.cast(authentication.getDetails()).getDomain() - : null; + String domainKey = SyncopeAuthenticationDetails.class.cast(authentication.getDetails()).getDomain(); if (StringUtils.isBlank(domainKey)) { domainKey = SyncopeConstants.MASTER_DOMAIN; } SyncopeAuthenticationDetails.class.cast(authentication.getDetails()).setDomain(domainKey); + boolean authenticated; if (anonymousUser.equals(authentication.getName())) { authenticated = authentication.getCredentials().toString().equals(anonymousKey); } else if (adminUser.equals(authentication.getName())) { @@ -152,67 +120,90 @@ public class SyncopeAuthenticationProvider implements AuthenticationProvider { CipherAlgorithm.valueOf(adminPasswordAlgorithm), adminPassword); } else { - Domain domain = domainDAO.find(domainKey); - if (domain == null) { - throw new NotFoundException("Could not find domain " + domainKey); - } - - authenticated = encryptor.verify( - authentication.getCredentials().toString(), - domain.getAdminCipherAlgorithm(), - domain.getAdminPwd()); + final String domainToFind = domainKey; + authenticated = execWithAuthContext(SyncopeConstants.MASTER_DOMAIN, new Executable<Boolean>() { + + @Override + public Boolean exec() { + Domain domain = dataAccessor.findDomain(domainToFind); + + return encryptor.verify( + authentication.getCredentials().toString(), + domain.getAdminCipherAlgorithm(), + domain.getAdminPwd()); + } + }); } } else { - User user = userDAO.find(authentication.getName()); - - if (user != null) { - if (user.isSuspended() != null && user.isSuspended()) { - throw new DisabledException("User " + user.getUsername() + " is suspended"); - } - - CPlainAttr authStatuses = confDAO.find("authentication.statuses"); - if (authStatuses != null && !authStatuses.getValuesAsStrings().contains(user.getStatus())) { - throw new DisabledException("User " + user.getUsername() + " not allowed to authenticate"); - } - - authenticated = authenticate(user, authentication.getCredentials().toString()); - - updateLoginAttributes(user, authenticated); + final Pair<Long, Boolean> authResult = + execWithAuthContext(domainKey, new Executable<Pair<Long, Boolean>>() { + + @Override + public Pair<Long, Boolean> exec() { + return dataAccessor.authenticate(authentication); + } + }); + authenticated = authResult.getValue(); + if (!authenticated) { + execWithAuthContext(domainKey, new Executable<Void>() { + + @Override + public Void exec() { + provisioningManager.internalSuspend(authResult.getKey()); + return null; + } + }); } } + final boolean isAuthenticated = authenticated; UsernamePasswordAuthenticationToken token; - if (authenticated) { - token = new UsernamePasswordAuthenticationToken( - authentication.getPrincipal(), - null, - userDetailsService.loadUserByUsername(authentication.getPrincipal().toString()).getAuthorities()); - token.setDetails(authentication.getDetails()); - - auditManager.audit( - AuditElements.EventCategoryType.REST, - AuditElements.AUTHENTICATION_CATEGORY, - null, - AuditElements.LOGIN_EVENT, - Result.SUCCESS, - null, - authenticated, - authentication, - "Successfully authenticated, with entitlements: " + token.getAuthorities()); + if (isAuthenticated) { + token = execWithAuthContext(domainKey, new Executable<UsernamePasswordAuthenticationToken>() { + + @Override + public UsernamePasswordAuthenticationToken exec() { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( + authentication.getPrincipal(), + null, + userDetailsService.loadUserByUsername(authentication.getPrincipal().toString()). + getAuthorities()); + token.setDetails(authentication.getDetails()); + + dataAccessor.audit( + AuditElements.EventCategoryType.REST, + AuditElements.AUTHENTICATION_CATEGORY, + null, + AuditElements.LOGIN_EVENT, + Result.SUCCESS, + null, + isAuthenticated, + authentication, + "Successfully authenticated, with entitlements: " + token.getAuthorities()); + return token; + } + }); LOG.debug("User {} successfully authenticated, with groups {}", authentication.getPrincipal(), token.getAuthorities()); } else { - auditManager.audit( - AuditElements.EventCategoryType.REST, - AuditElements.AUTHENTICATION_CATEGORY, - null, - AuditElements.LOGIN_EVENT, - Result.FAILURE, - null, - authenticated, - authentication, - "User " + authentication.getPrincipal() + " not authenticated"); + execWithAuthContext(domainKey, new Executable<Void>() { + + @Override + public Void exec() { + dataAccessor.audit( + AuditElements.EventCategoryType.REST, + AuditElements.AUTHENTICATION_CATEGORY, + null, + AuditElements.LOGIN_EVENT, + Result.FAILURE, + null, + isAuthenticated, + authentication, + "User " + authentication.getPrincipal() + " not authenticated"); + return null; + } + }); LOG.debug("User {} not authenticated", authentication.getPrincipal()); @@ -222,84 +213,13 @@ public class SyncopeAuthenticationProvider implements AuthenticationProvider { return token; } - protected void updateLoginAttributes(final User user, final boolean authenticated) { - boolean userModified = false; - - if (authenticated) { - if (confDAO.find("log.lastlogindate", Boolean.toString(true)).getValues().get(0).getBooleanValue()) { - user.setLastLoginDate(new Date()); - userModified = true; - } - - if (user.getFailedLogins() != 0) { - user.setFailedLogins(0); - userModified = true; - } - } else { - user.setFailedLogins(user.getFailedLogins() + 1); - userModified = true; - } - - if (userModified) { - userDAO.save(user); - } - } - - protected Set<? extends ExternalResource> getPassthroughResources(final User user) { - Set<? extends ExternalResource> result = null; - - // 1. look for assigned resources, pick the ones whose account policy has authentication resources - for (ExternalResource resource : userDAO.findAllResources(user)) { - if (resource.getAccountPolicy() != null && !resource.getAccountPolicy().getResources().isEmpty()) { - if (result == null) { - result = resource.getAccountPolicy().getResources(); - } else { - result.retainAll(resource.getAccountPolicy().getResources()); - } - } - } - - // 2. look for realms, pick the ones whose account policy has authentication resources - for (Realm realm : realmDAO.findAncestors(user.getRealm())) { - if (realm.getAccountPolicy() != null && !realm.getAccountPolicy().getResources().isEmpty()) { - if (result == null) { - result = realm.getAccountPolicy().getResources(); - } else { - result.retainAll(realm.getAccountPolicy().getResources()); - } - } - } - - return SetUtils.emptyIfNull(result); - } - - protected boolean authenticate(final User user, final String password) { - boolean authenticated = encryptor.verify(password, user.getCipherAlgorithm(), user.getPassword()); - LOG.debug("{} authenticated on internal storage: {}", user.getUsername(), authenticated); - - for (Iterator<? extends ExternalResource> itor = getPassthroughResources(user).iterator(); - itor.hasNext() && !authenticated;) { - - ExternalResource resource = itor.next(); - String connObjectKey = null; - try { - connObjectKey = MappingUtils.getConnObjectKeyValue(user, resource.getProvision(anyTypeDAO.findUser())); - Uid uid = connFactory.getConnector(resource).authenticate(connObjectKey, password, null); - if (uid != null) { - authenticated = true; - } - } catch (Exception e) { - LOG.debug("Could not authenticate {} on {}", user.getUsername(), resource.getKey(), e); - } - LOG.debug("{} authenticated on {} as {}: {}", - user.getUsername(), resource.getKey(), connObjectKey, authenticated); - } - - return authenticated; - } - @Override public boolean supports(final Class<? extends Object> type) { return type.equals(UsernamePasswordAuthenticationToken.class); } + + protected interface Executable<T> { + + T exec(); + } } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java ---------------------------------------------------------------------- diff --git a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java index a179e75..70ec6ac 100644 --- a/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java +++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/SyncopeUserDetailsService.java @@ -18,104 +18,20 @@ */ package org.apache.syncope.core.misc.security; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.annotation.Resource; -import org.apache.commons.collections4.Closure; -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.IteratorUtils; -import org.apache.commons.collections4.PredicateUtils; -import org.apache.commons.collections4.Transformer; -import org.apache.syncope.common.lib.SyncopeConstants; -import org.apache.syncope.common.lib.types.Entitlement; -import org.apache.syncope.core.misc.RealmUtils; -import org.apache.syncope.core.persistence.api.dao.GroupDAO; -import org.apache.syncope.core.persistence.api.dao.UserDAO; -import org.apache.syncope.core.persistence.api.entity.Realm; -import org.apache.syncope.core.persistence.api.entity.Role; -import org.apache.syncope.core.persistence.api.entity.group.Group; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; @Configurable public class SyncopeUserDetailsService implements UserDetailsService { @Autowired - protected UserDAO userDAO; - - @Autowired - protected GroupDAO groupDAO; - - @Resource(name = "adminUser") - protected String adminUser; - - @Resource(name = "anonymousUser") - protected String anonymousUser; + protected AuthDataAccessor dataAccessor; @Override public UserDetails loadUserByUsername(final String username) { - final Set<SyncopeGrantedAuthority> authorities = new HashSet<>(); - if (anonymousUser.equals(username)) { - authorities.add(new SyncopeGrantedAuthority(Entitlement.ANONYMOUS)); - } else if (adminUser.equals(username)) { - CollectionUtils.collect(IteratorUtils.filteredIterator(Entitlement.values().iterator(), - PredicateUtils.notPredicate(PredicateUtils.equalPredicate(Entitlement.ANONYMOUS))), - new Transformer<String, SyncopeGrantedAuthority>() { - - @Override - public SyncopeGrantedAuthority transform(final String entitlement) { - return new SyncopeGrantedAuthority(entitlement, SyncopeConstants.ROOT_REALM); - } - }, - authorities); - } else { - org.apache.syncope.core.persistence.api.entity.user.User user = userDAO.find(username); - if (user == null) { - throw new UsernameNotFoundException("Could not find any user with id " + username); - } - - // Give entitlements as assigned by roles (with realms, where applicable) - assigned either - // statically and dynamically - for (final Role role : userDAO.findAllRoles(user)) { - CollectionUtils.forAllDo(role.getEntitlements(), new Closure<String>() { - - @Override - public void execute(final String entitlement) { - SyncopeGrantedAuthority authority = new SyncopeGrantedAuthority(entitlement); - authorities.add(authority); - - List<String> realmFullPahs = new ArrayList<>(); - CollectionUtils.collect(role.getRealms(), new Transformer<Realm, String>() { - - @Override - public String transform(final Realm realm) { - return realm.getFullPath(); - } - }, realmFullPahs); - authority.addRealms(realmFullPahs); - } - }); - } - - // Give group entitlements for owned groups - for (Group group : groupDAO.findOwnedByUser(user.getKey())) { - for (String entitlement : Arrays.asList( - Entitlement.GROUP_READ, Entitlement.GROUP_UPDATE, Entitlement.GROUP_DELETE)) { - - SyncopeGrantedAuthority authority = new SyncopeGrantedAuthority(entitlement); - authority.addRealm(RealmUtils.getGroupOwnerRealm(group.getRealm().getFullPath(), group.getKey())); - authorities.add(authority); - } - } - } - - return new User(username, "<PASSWORD_PLACEHOLDER>", authorities); + return new User(username, "<PASSWORD_PLACEHOLDER>", dataAccessor.load(username)); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/misc/src/main/resources/securityContext.xml ---------------------------------------------------------------------- diff --git a/core/misc/src/main/resources/securityContext.xml b/core/misc/src/main/resources/securityContext.xml index 57b1980..1022815 100644 --- a/core/misc/src/main/resources/securityContext.xml +++ b/core/misc/src/main/resources/securityContext.xml @@ -62,6 +62,8 @@ under the License. <security:csrf disabled="true"/> </security:http> + <bean class="org.apache.syncope.core.misc.security.AuthDataAccessor"/> + <bean id="syncopeUserDetailsService" class="org.apache.syncope.core.misc.security.SyncopeUserDetailsService"/> <bean id="syncopeAuthenticationProvider" class="org.apache.syncope.core.misc.security.SyncopeAuthenticationProvider"> http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java index a1e4d09..3fc9b99 100644 --- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java +++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/UserDAO.java @@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.api.dao; import java.util.Collection; import java.util.List; +import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.core.persistence.api.entity.Role; import org.apache.syncope.core.persistence.api.entity.group.Group; import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource; @@ -49,4 +50,6 @@ public interface UserDAO extends AnyDAO<User> { Collection<ExternalResource> findAllResources(User user); Collection<String> findAllResourceNames(User user); + + Pair<Boolean, Boolean> enforcePolicies(User user); } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADomainDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADomainDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADomainDAO.java index b3bb188..eeee97c 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADomainDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPADomainDAO.java @@ -24,10 +24,12 @@ import org.apache.syncope.core.persistence.api.dao.DomainDAO; import org.apache.syncope.core.persistence.api.entity.Domain; import org.apache.syncope.core.persistence.jpa.entity.JPADomain; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; @Repository public class JPADomainDAO extends AbstractDAO<Domain, String> implements DomainDAO { + @Transactional(readOnly = true) @Override public Domain find(final String key) { return entityManager().find(JPADomain.class, key); http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java ---------------------------------------------------------------------- diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java index 50564f2..4e9afe1 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPAUserDAO.java @@ -63,7 +63,6 @@ import org.apache.syncope.core.persistence.api.entity.user.UMembership; import org.apache.syncope.core.persistence.jpa.entity.JPAAnyUtilsFactory; import org.apache.syncope.core.persistence.jpa.entity.user.JPADynRoleMembership; import org.apache.syncope.core.persistence.jpa.entity.user.JPAUDynGroupMembership; -import org.apache.syncope.core.provisioning.api.UserSuspender; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Propagation; @@ -96,9 +95,6 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO { @Autowired private AccountPolicyEnforcer apEnforcer; - @Autowired(required = false) - private UserSuspender suspender; - @Override protected AnyUtils init() { return new JPAAnyUtilsFactory().getInstance(AnyTypeKind.USER); @@ -210,11 +206,9 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO { private List<AccountPolicy> getAccountPolicies(final User user) { List<AccountPolicy> policies = new ArrayList<>(); - AccountPolicy policy; - // add resource policies for (ExternalResource resource : findAllResources(user)) { - policy = resource.getAccountPolicy(); + AccountPolicy policy = resource.getAccountPolicy(); if (policy != null) { policies.add(policy); } @@ -222,7 +216,7 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO { // add realm policies for (Realm realm : realmDAO.findAncestors(user.getRealm())) { - policy = realm.getAccountPolicy(); + AccountPolicy policy = realm.getAccountPolicy(); if (policy != null) { policies.add(policy); } @@ -231,7 +225,9 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO { return policies; } - private Pair<Boolean, Boolean> enforcePolicies(final User user) { + @Transactional(readOnly = true) + @Override + public Pair<Boolean, Boolean> enforcePolicies(final User user) { // ------------------------------ // Verify password policies // ------------------------------ @@ -310,18 +306,13 @@ public class JPAUserDAO extends AbstractAnyDAO<User> implements UserDAO { JPAUser.class.cast(merged).setClearPassword(clearPwd); // 4. enforce password and account policies - Pair<Boolean, Boolean> enforceSuspend = null; try { - enforceSuspend = enforcePolicies(merged); + enforcePolicies(merged); } catch (InvalidEntityException e) { entityManager().remove(merged); throw e; } - if (suspender != null && enforceSuspend.getKey()) { - suspender.suspend(user, enforceSuspend.getValue()); - } - roleDAO.refreshDynMemberships(merged); groupDAO.refreshDynMemberships(merged); http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java ---------------------------------------------------------------------- diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java index 3378707..21acad2 100644 --- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java +++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserProvisioningManager.java @@ -26,7 +26,6 @@ import org.apache.syncope.common.lib.mod.StatusMod; import org.apache.syncope.common.lib.mod.UserMod; import org.apache.syncope.common.lib.to.PropagationStatus; import org.apache.syncope.common.lib.to.UserTO; -import org.apache.syncope.core.persistence.api.entity.user.User; import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult; public interface UserProvisioningManager extends ProvisioningManager<UserTO, UserMod> { @@ -37,7 +36,7 @@ public interface UserProvisioningManager extends ProvisioningManager<UserTO, Use Pair<Long, List<PropagationStatus>> suspend(StatusMod statusMod); - void innerSuspend(User user, boolean propagate); + void internalSuspend(Long key); Pair<Long, List<PropagationStatus>> create(UserTO userTO, boolean storePassword); http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserSuspender.java ---------------------------------------------------------------------- diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserSuspender.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserSuspender.java deleted file mode 100644 index 610513c..0000000 --- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/UserSuspender.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.syncope.core.provisioning.api; - -import org.apache.syncope.core.persistence.api.entity.user.User; - -public interface UserSuspender { - - void suspend(User user, boolean propagateSuspension); -} http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java index 0809607..38264de 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultUserProvisioningManager.java @@ -288,19 +288,18 @@ public class DefaultUserProvisioningManager implements UserProvisioningManager { } @Override - public void innerSuspend(final User user, final boolean propagate) { - final WorkflowResult<Long> updated = uwfAdapter.suspend(user); + public void internalSuspend(final Long key) { + Pair<WorkflowResult<Long>, Boolean> updated = uwfAdapter.internalSuspend(key); // propagate suspension if and only if it is required by policy - if (propagate) { + if (updated != null && updated.getValue()) { UserMod userMod = new UserMod(); - userMod.setKey(updated.getResult()); + userMod.setKey(updated.getKey().getResult()); - final List<PropagationTask> tasks = propagationManager.getUserUpdateTasks( + List<PropagationTask> tasks = propagationManager.getUserUpdateTasks( new WorkflowResult<Pair<UserMod, Boolean>>( new ImmutablePair<>(userMod, Boolean.FALSE), - updated.getPropByRes(), updated.getPerformedTasks())); - + updated.getKey().getPropByRes(), updated.getKey().getPerformedTasks())); taskExecutor.execute(tasks); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/UserSuspenderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/UserSuspenderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/UserSuspenderImpl.java deleted file mode 100644 index 7ff9e84..0000000 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/UserSuspenderImpl.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.syncope.core.provisioning.java; - -import org.apache.syncope.core.persistence.api.entity.user.User; -import org.apache.syncope.core.provisioning.api.UserSuspender; -import org.apache.syncope.core.provisioning.api.UserProvisioningManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class UserSuspenderImpl implements UserSuspender { - - private static final Logger LOG = LoggerFactory.getLogger(UserSuspenderImpl.class); - - @Autowired - private UserProvisioningManager provisioningManager; - - @Override - public void suspend(final User user, final boolean suspend) { - try { - LOG.debug("User {}:{} is over to max failed logins", user.getKey(), user.getUsername()); - - // reduce failed logins number to avoid multiple request - user.setFailedLogins(user.getFailedLogins() - 1); - - // disable user and propagate suspension if and only if it is required by policy - provisioningManager.innerSuspend(user, suspend); - } catch (Exception e) { - LOG.error("Error during user suspension", e); - } - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java ---------------------------------------------------------------------- diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java index f52b941..459c052 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/UserDataBinderImpl.java @@ -88,7 +88,7 @@ public class UserDataBinderImpl extends AbstractAnyDataBinder implements UserDat public UserTO getAuthenticatedUserTO() { final UserTO authUserTO; - final String authUsername = AuthContextUtils.getUsername(); + String authUsername = AuthContextUtils.getUsername(); if (anonymousUser.equals(authUsername)) { authUserTO = new UserTO(); authUserTO.setKey(-2); http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java ---------------------------------------------------------------------- diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java index 391aea8..2447697 100644 --- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java +++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserServiceImpl.java @@ -62,12 +62,11 @@ public class UserServiceImpl extends AbstractAnyService<UserTO, UserMod> impleme } @Override - public Response status(final Long key, final StatusMod statusMod) { - UserTO user = logic.read(key); + public Response status(final StatusMod statusMod) { + UserTO user = logic.read(statusMod.getKey()); checkETag(user.getETagValue()); - statusMod.setKey(key); UserTO updated = logic.status(statusMod); return modificationResponse(updated); } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java ---------------------------------------------------------------------- diff --git a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java index 1ce0d97..7a4ba38 100644 --- a/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java +++ b/core/workflow-activiti/src/main/java/org/apache/syncope/core/workflow/activiti/ActivitiUserWorkflowAdapter.java @@ -74,8 +74,6 @@ import org.apache.syncope.core.provisioning.api.data.UserDataBinder; import org.apache.syncope.core.workflow.api.WorkflowDefinitionFormat; import org.apache.syncope.core.workflow.api.WorkflowException; import org.apache.syncope.core.workflow.java.AbstractUserWorkflowAdapter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -84,8 +82,6 @@ import org.springframework.transaction.annotation.Transactional; */ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter { - protected static final Logger LOG = LoggerFactory.getLogger(ActivitiUserWorkflowAdapter.class); - protected static final String[] PROPERTY_IGNORE_PROPS = { "type" }; public static final String WF_PROCESS_ID = "userWorkflow"; @@ -279,7 +275,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter { protected Set<String> doExecuteTask(final User user, final String task, final Map<String, Object> moreVariables) { Set<String> preTasks = getPerformedTasks(user); - final Map<String, Object> variables = new HashMap<>(); + Map<String, Object> variables = new HashMap<>(); variables.put(WF_EXECUTOR, AuthContextUtils.getUsername()); variables.put(TASK, task); @@ -345,7 +341,6 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter { } @Override - @Transactional(rollbackFor = { Throwable.class }) protected WorkflowResult<Long> doSuspend(final User user) { Set<String> performedTasks = doExecuteTask(user, "suspend", null); updateStatus(user); @@ -661,7 +656,7 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter { public List<WorkflowFormTO> getForms() { List<WorkflowFormTO> forms = new ArrayList<>(); - final String authUser = AuthContextUtils.getUsername(); + String authUser = AuthContextUtils.getUsername(); if (adminUser.equals(authUser)) { forms.addAll(getForms(engine.getTaskService().createTaskQuery(). taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE))); @@ -772,10 +767,9 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter { return new ImmutablePair<>(task, formData); } - @Transactional @Override public WorkflowFormTO claimForm(final String taskId) { - final String authUser = AuthContextUtils.getUsername(); + String authUser = AuthContextUtils.getUsername(); Pair<Task, TaskFormData> checked = checkTask(taskId, authUser); if (!adminUser.equals(authUser)) { @@ -798,10 +792,9 @@ public class ActivitiUserWorkflowAdapter extends AbstractUserWorkflowAdapter { return getFormTO(task, checked.getValue()); } - @Transactional @Override public WorkflowResult<UserMod> submitForm(final WorkflowFormTO form) { - final String authUser = AuthContextUtils.getUsername(); + String authUser = AuthContextUtils.getUsername(); Pair<Task, TaskFormData> checked = checkTask(form.getTaskId(), authUser); if (!checked.getKey().getOwner().equals(authUser)) { http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java ---------------------------------------------------------------------- diff --git a/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java b/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java index fbf29c3..7122b84 100644 --- a/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java +++ b/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/UserWorkflowAdapter.java @@ -22,7 +22,6 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.core.provisioning.api.WorkflowResult; import org.apache.syncope.common.lib.mod.UserMod; import org.apache.syncope.common.lib.to.UserTO; -import org.apache.syncope.core.persistence.api.entity.user.User; /** * Interface for calling underlying workflow implementations. @@ -96,12 +95,12 @@ public interface UserWorkflowAdapter extends WorkflowAdapter { WorkflowResult<Long> suspend(Long key); /** - * Suspend an user. + * Suspend an user (used by internal authentication process) * - * @param user user to be suspended - * @return user just suspended + * @param key to be suspended + * @return user just suspended and information whether to propagate suspension */ - WorkflowResult<Long> suspend(User user); + Pair<WorkflowResult<Long>, Boolean> internalSuspend(Long key); /** * Reactivate an user. http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java ---------------------------------------------------------------------- diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java index ecc1c01..b829137 100644 --- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java +++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/AbstractUserWorkflowAdapter.java @@ -18,6 +18,7 @@ */ package org.apache.syncope.core.workflow.java; +import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.common.lib.mod.UserMod; import org.apache.syncope.core.persistence.api.dao.UserDAO; @@ -28,6 +29,8 @@ import org.apache.syncope.core.provisioning.api.data.UserDataBinder; import org.apache.syncope.core.workflow.api.UserWorkflowAdapter; import org.identityconnectors.common.Base64; import org.identityconnectors.common.security.EncryptorFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -35,6 +38,8 @@ import org.springframework.transaction.annotation.Transactional; @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = { Throwable.class }) public abstract class AbstractUserWorkflowAdapter implements UserWorkflowAdapter { + protected static final Logger LOG = LoggerFactory.getLogger(UserWorkflowAdapter.class); + @Autowired protected UserDataBinder dataBinder; @@ -62,8 +67,8 @@ public abstract class AbstractUserWorkflowAdapter implements UserWorkflowAdapter protected abstract WorkflowResult<Long> doActivate(User user, String token); @Override - public WorkflowResult<Long> activate(final Long userKey, final String token) { - return doActivate(userDAO.authFind(userKey), token); + public WorkflowResult<Long> activate(final Long key, final String token) { + return doActivate(userDAO.authFind(key), token); } protected abstract WorkflowResult<Pair<UserMod, Boolean>> doUpdate(User user, UserMod userMod); @@ -76,23 +81,42 @@ public abstract class AbstractUserWorkflowAdapter implements UserWorkflowAdapter protected abstract WorkflowResult<Long> doSuspend(User user); @Override - public WorkflowResult<Long> suspend(final Long userKey) { - return suspend(userDAO.authFind(userKey)); - } + public WorkflowResult<Long> suspend(final Long key) { + User user = userDAO.authFind(key); - @Override - public WorkflowResult<Long> suspend(final User user) { // set suspended flag user.setSuspended(Boolean.TRUE); return doSuspend(user); } + @Override + public Pair<WorkflowResult<Long>, Boolean> internalSuspend(final Long key) { + User user = userDAO.authFind(key); + + Pair<WorkflowResult<Long>, Boolean> result = null; + + Pair<Boolean, Boolean> enforce = userDAO.enforcePolicies(user); + if (enforce.getKey()) { + LOG.debug("User {} {} is over the max failed logins", user.getKey(), user.getUsername()); + + // reduce failed logins number to avoid multiple request + user.setFailedLogins(user.getFailedLogins() - 1); + + // set suspended flag + user.setSuspended(Boolean.TRUE); + + result = ImmutablePair.of(doSuspend(user), enforce.getValue()); + } + + return result; + } + protected abstract WorkflowResult<Long> doReactivate(User user); @Override - public WorkflowResult<Long> reactivate(final Long userKey) { - final User user = userDAO.authFind(userKey); + public WorkflowResult<Long> reactivate(final Long key) { + User user = userDAO.authFind(key); // reset failed logins user.setFailedLogins(0); @@ -106,21 +130,21 @@ public abstract class AbstractUserWorkflowAdapter implements UserWorkflowAdapter protected abstract void doRequestPasswordReset(User user); @Override - public void requestPasswordReset(final Long userKey) { - doRequestPasswordReset(userDAO.authFind(userKey)); + public void requestPasswordReset(final Long key) { + doRequestPasswordReset(userDAO.authFind(key)); } protected abstract void doConfirmPasswordReset(User user, String token, String password); @Override - public void confirmPasswordReset(final Long userKey, final String token, final String password) { - doConfirmPasswordReset(userDAO.authFind(userKey), token, password); + public void confirmPasswordReset(final Long key, final String token, final String password) { + doConfirmPasswordReset(userDAO.authFind(key), token, password); } protected abstract void doDelete(User user); @Override - public void delete(final Long userKey) { - doDelete(userDAO.authFind(userKey)); + public void delete(final Long key) { + doDelete(userDAO.authFind(key)); } } http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/AbstractCamelProvisioningManager.java ---------------------------------------------------------------------- diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/AbstractCamelProvisioningManager.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/AbstractCamelProvisioningManager.java index 516e798..1a6d7df 100644 --- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/AbstractCamelProvisioningManager.java +++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/AbstractCamelProvisioningManager.java @@ -68,7 +68,7 @@ abstract class AbstractCamelProvisioningManager { template.send(uri, exchange); } - protected void sendMessage(final String uri, final Object obj, final Map<String, Object> properties) { + protected void sendMessage(final String uri, final Object body, final Map<String, Object> properties) { Exchange exchange = new DefaultExchange(getContext()); for (Map.Entry<String, Object> property : properties.entrySet()) { @@ -77,7 +77,7 @@ abstract class AbstractCamelProvisioningManager { } DefaultMessage message = new DefaultMessage(); - message.setBody(obj); + message.setBody(body); exchange.setIn(message); ProducerTemplate template = getContext().createProducerTemplate(); template.send(uri, exchange); http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java ---------------------------------------------------------------------- diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java index 8b5ad89..fa0b84b 100644 --- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java +++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/CamelUserProvisioningManager.java @@ -34,7 +34,6 @@ import org.apache.syncope.common.lib.mod.UserMod; import org.apache.syncope.common.lib.to.PropagationStatus; import org.apache.syncope.common.lib.to.UserTO; import org.apache.syncope.common.lib.types.PropagationByResource; -import org.apache.syncope.core.persistence.api.entity.user.User; import org.apache.syncope.core.provisioning.api.UserProvisioningManager; import org.apache.syncope.core.provisioning.api.WorkflowResult; import org.apache.syncope.core.provisioning.api.sync.ProvisioningResult; @@ -319,13 +318,10 @@ public class CamelUserProvisioningManager extends AbstractCamelProvisioningManag } @Override - public void innerSuspend(final User user, final boolean propagate) { - PollingConsumer pollingConsumer = getConsumer("direct:innerSuspendUserPort"); + public void internalSuspend(final Long key) { + PollingConsumer pollingConsumer = getConsumer("direct:internalSuspendUserPort"); - Map<String, Object> props = new HashMap<>(); - props.put("propagate", propagate); - - sendMessage("direct:innerSuspendUser", user.getKey(), props); + sendMessage("direct:internalSuspendUser", key); Exchange exchange = pollingConsumer.receive(); http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserInnerSuspendProcessor.java ---------------------------------------------------------------------- diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserInnerSuspendProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserInnerSuspendProcessor.java deleted file mode 100644 index be3e6ac..0000000 --- a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserInnerSuspendProcessor.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.apache.syncope.core.provisioning.camel.processor; - -import java.util.List; -import org.apache.camel.Exchange; -import org.apache.camel.Processor; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.syncope.common.lib.mod.UserMod; -import org.apache.syncope.core.persistence.api.entity.task.PropagationTask; -import org.apache.syncope.core.provisioning.api.WorkflowResult; -import org.apache.syncope.core.provisioning.api.propagation.PropagationManager; -import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -@Component -public class UserInnerSuspendProcessor implements Processor { - - @Autowired - protected PropagationManager propagationManager; - - @Autowired - protected PropagationTaskExecutor taskExecutor; - - @Override - public void process(final Exchange exchange) { - @SuppressWarnings("unchecked") - WorkflowResult<Long> updated = (WorkflowResult) exchange.getIn().getBody(); - Boolean propagate = exchange.getProperty("propagate", Boolean.class); - - if (propagate) { - UserMod userMod = new UserMod(); - userMod.setKey(updated.getResult()); - - List<PropagationTask> tasks = propagationManager.getUserUpdateTasks( - new WorkflowResult<Pair<UserMod, Boolean>>( - new ImmutablePair<>(userMod, Boolean.FALSE), - updated.getPropByRes(), updated.getPerformedTasks())); - taskExecutor.execute(tasks); - } - } - -} http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserInternalSuspendProcessor.java ---------------------------------------------------------------------- diff --git a/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserInternalSuspendProcessor.java b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserInternalSuspendProcessor.java new file mode 100644 index 0000000..73e63ad --- /dev/null +++ b/ext/camel/provisioning-camel/src/main/java/org/apache/syncope/core/provisioning/camel/processor/UserInternalSuspendProcessor.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.syncope.core.provisioning.camel.processor; + +import java.util.List; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.syncope.common.lib.mod.UserMod; +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask; +import org.apache.syncope.core.provisioning.api.WorkflowResult; +import org.apache.syncope.core.provisioning.api.propagation.PropagationManager; +import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class UserInternalSuspendProcessor implements Processor { + + @Autowired + protected PropagationManager propagationManager; + + @Autowired + protected PropagationTaskExecutor taskExecutor; + + @Override + public void process(final Exchange exchange) { + @SuppressWarnings("unchecked") + Pair<WorkflowResult<Long>, Boolean> updated = (Pair) exchange.getIn().getBody(); + + // propagate suspension if and only if it is required by policy + if (updated != null && updated.getValue()) { + UserMod userMod = new UserMod(); + userMod.setKey(updated.getKey().getResult()); + + List<PropagationTask> tasks = propagationManager.getUserUpdateTasks( + new WorkflowResult<Pair<UserMod, Boolean>>( + new ImmutablePair<>(userMod, Boolean.FALSE), + updated.getKey().getPropByRes(), updated.getKey().getPerformedTasks())); + taskExecutor.execute(tasks); + } + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml ---------------------------------------------------------------------- diff --git a/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml b/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml index aca6a46..38e48f3 100644 --- a/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml +++ b/ext/camel/provisioning-camel/src/main/resources/userRoutes.xml @@ -198,18 +198,18 @@ under the License. <to uri="direct:deprovisionPort"/> </route> - <route id="innerSuspendUser"> - <from uri="direct:innerSuspendUser"/> + <route id="internalSuspendUser"> + <from uri="direct:internalSuspendUser"/> <doTry> - <bean ref="uwfAdapter" method="suspend(${body})"/> - <process ref="userInnerSuspendProcessor"/> - <to uri="direct:innerSuspendUserPort"/> + <bean ref="uwfAdapter" method="internalSuspend(${body})"/> + <process ref="userInternalSuspendProcessor"/> + <to uri="direct:internalSuspendUserPort"/> <doCatch> <exception>java.lang.RuntimeException</exception> <handled> <constant>false</constant> </handled> - <to uri="direct:innerSuspendUserPort"/> + <to uri="direct:internalSuspendUserPort"/> </doCatch> </doTry> </route> http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java index 9d810b6..6378631 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/AuthenticationITCase.java @@ -258,7 +258,7 @@ public class AuthenticationITCase extends AbstractITCase { assertEquals(0, getFailedLogins(userService4, userId)); } - //@Test + @Test public void checkUserSuspension() { UserTO userTO = UserITCase.getUniqueSampleTO("[email protected]"); userTO.setRealm("/odd"); @@ -292,8 +292,9 @@ public class AuthenticationITCase extends AbstractITCase { assertReadFails(goodPwdClient); StatusMod reactivate = new StatusMod(); + reactivate.setKey(userTO.getKey()); reactivate.setType(StatusMod.ModType.REACTIVATE); - userTO = userService.status(userTO.getKey(), reactivate).readEntity(UserTO.class); + userTO = userService.status(reactivate).readEntity(UserTO.class); assertNotNull(userTO); assertEquals("active", userTO.getStatus()); http://git-wip-us.apache.org/repos/asf/syncope/blob/5cf6aae8/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java ---------------------------------------------------------------------- diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java index 4cecdf7..048259d 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/reference/UserITCase.java @@ -818,9 +818,10 @@ public class UserITCase extends AbstractITCase { assertEquals("created", userTO.getStatus()); StatusMod statusMod = new StatusMod(); + statusMod.setKey(userTO.getKey()); statusMod.setType(StatusMod.ModType.ACTIVATE); statusMod.setToken(userTO.getToken()); - userTO = userService.status(userTO.getKey(), statusMod).readEntity(UserTO.class); + userTO = userService.status(statusMod).readEntity(UserTO.class); assertNotNull(userTO); assertNull(userTO.getToken()); @@ -844,14 +845,16 @@ public class UserITCase extends AbstractITCase { : "created", userTO.getStatus()); StatusMod statusMod = new StatusMod(); + statusMod.setKey(userTO.getKey()); statusMod.setType(StatusMod.ModType.SUSPEND); - userTO = userService.status(userTO.getKey(), statusMod).readEntity(UserTO.class); + userTO = userService.status(statusMod).readEntity(UserTO.class); assertNotNull(userTO); assertEquals("suspended", userTO.getStatus()); statusMod = new StatusMod(); + statusMod.setKey(userTO.getKey()); statusMod.setType(StatusMod.ModType.REACTIVATE); - userTO = userService.status(userTO.getKey(), statusMod).readEntity(UserTO.class); + userTO = userService.status(statusMod).readEntity(UserTO.class); assertNotNull(userTO); assertEquals("active", userTO.getStatus()); } @@ -875,50 +878,53 @@ public class UserITCase extends AbstractITCase { assertEquals(ActivitiDetector.isActivitiEnabledForUsers(syncopeService) ? "active" : "created", userTO.getStatus()); - long userId = userTO.getKey(); + long userKey = userTO.getKey(); // Suspend with effect on syncope, ldap and db => user should be suspended in syncope and all resources StatusMod statusMod = new StatusMod(); + statusMod.setKey(userKey); statusMod.setType(StatusMod.ModType.SUSPEND); statusMod.setOnSyncope(true); statusMod.getResourceNames().add(RESOURCE_NAME_TESTDB); statusMod.getResourceNames().add(RESOURCE_NAME_LDAP); - userTO = userService.status(userId, statusMod).readEntity(UserTO.class); + userTO = userService.status(statusMod).readEntity(UserTO.class); assertNotNull(userTO); assertEquals("suspended", userTO.getStatus()); ConnObjectTO connObjectTO = - resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userId); + resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey); assertFalse(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME)); - connObjectTO = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userId); + connObjectTO = resourceService.readConnObject(RESOURCE_NAME_LDAP, AnyTypeKind.USER.name(), userKey); assertNotNull(connObjectTO); // Suspend and reactivate only on ldap => db and syncope should still show suspended statusMod = new StatusMod(); + statusMod.setKey(userKey); statusMod.setType(StatusMod.ModType.SUSPEND); statusMod.setOnSyncope(false); statusMod.getResourceNames().add(RESOURCE_NAME_LDAP); - userService.status(userId, statusMod); + userService.status(statusMod); statusMod.setType(StatusMod.ModType.REACTIVATE); - userTO = userService.status(userId, statusMod).readEntity(UserTO.class); + userTO = userService.status(statusMod).readEntity(UserTO.class); assertNotNull(userTO); assertEquals("suspended", userTO.getStatus()); - connObjectTO = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userId); + connObjectTO = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey); assertFalse(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME)); // Reactivate on syncope and db => syncope and db should show the user as active statusMod = new StatusMod(); + statusMod.setKey(userKey); statusMod.setType(StatusMod.ModType.REACTIVATE); statusMod.setOnSyncope(true); statusMod.getResourceNames().add(RESOURCE_NAME_TESTDB); - userTO = userService.status(userId, statusMod).readEntity(UserTO.class); + userTO = userService.status(statusMod).readEntity(UserTO.class); assertNotNull(userTO); assertEquals("active", userTO.getStatus()); - connObjectTO = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userId); + connObjectTO = resourceService.readConnObject(RESOURCE_NAME_TESTDB, AnyTypeKind.USER.name(), userKey); assertTrue(getBooleanAttribute(connObjectTO, OperationalAttributes.ENABLE_NAME)); } @@ -1795,7 +1801,8 @@ public class UserITCase extends AbstractITCase { final ResourceAssociationMod associationMod = new ResourceAssociationMod(); associationMod.getTargetResources().addAll(CollectionWrapper.wrap(RESOURCE_NAME_CSV, ResourceKey.class)); - assertNotNull(userService.associate(actual.getKey(), ResourceAssociationAction.LINK, associationMod).readEntity(BulkActionResult.class)); + assertNotNull(userService.associate(actual.getKey(), ResourceAssociationAction.LINK, associationMod).readEntity( + BulkActionResult.class)); actual = userService.read(actual.getKey()); assertNotNull(actual);
