/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.4 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.security.internal; import com.google.common.collect.Lists; import com.qcadoo.model.api.DataDefinitionService; import com.qcadoo.model.api.Entity; import com.qcadoo.model.api.aop.Monitorable; import com.qcadoo.model.api.search.SearchOrders; import com.qcadoo.model.api.search.SearchRestrictions; import com.qcadoo.security.api.SecurityRole; import com.qcadoo.security.api.SecurityRolesService; import com.qcadoo.security.constants.*; import com.qcadoo.security.internal.api.InternalSecurityService; import com.qcadoo.security.internal.api.QcadooUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; import org.springframework.security.authentication.event.AbstractAuthenticationEvent; import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.context.SecurityContextHolder; 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; import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken; import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository; import org.springframework.stereotype.Service; import java.util.Calendar; import java.util.Date; import java.util.List; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; @Service("userDetailsService") public class SecurityServiceImpl implements InternalSecurityService, UserDetailsService, PersistentTokenRepository, ApplicationListener<AbstractAuthenticationEvent> { private static final String L_TARGET_ROLE_IDENTIFIER_MUST_BE_GIVEN = "targetRoleIdetifier must be given"; private static final String L_USER_ENTITY_MUST_BE_GIVEN = "User entity must be given";; @Autowired private DataDefinitionService dataDefinitionService; @Autowired private SecurityRolesService securityRolesService; @Override public void onApplicationEvent(final AbstractAuthenticationEvent event) { if (!(event instanceof AbstractAuthenticationFailureEvent)) { UserDetails userDetails = (UserDetails) event.getAuthentication().getPrincipal(); Entity user = dataDefinitionService .get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_USER).find() .add(SearchRestrictions.eq(UserFields.USER_NAME, userDetails.getUsername())).uniqueResult(); Calendar now = Calendar.getInstance(); now.add(Calendar.DAY_OF_YEAR, -1); if ((user.getField(UserFields.LAST_ACTIVITY) == null) || now.getTime().after(user.getDateField(UserFields.LAST_ACTIVITY))) { user.setField(UserFields.LAST_ACTIVITY, new Date()); dataDefinitionService.get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_USER).save( user); } } } @Override @Monitorable public String getCurrentUserName() { if ((SecurityContextHolder.getContext() == null) || (SecurityContextHolder.getContext().getAuthentication() == null) || (SecurityContextHolder.getContext().getAuthentication().getName() == null)) { return null; } String userName = SecurityContextHolder.getContext().getAuthentication().getName(); Entity user = getUserEntity(userName); checkNotNull(user, "Current user with login %s cannot be found", userName); return user.getStringField(UserFields.USER_NAME); } @Override public List<QcadooUser> getUsers() { List<Entity> users = dataDefinitionService .get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_USER).find() .addOrder(SearchOrders.asc(UserFields.USER_NAME)).list().getEntities(); List<QcadooUser> qcadooUsers = Lists.newLinkedList(); for (Entity user : users) { qcadooUsers.add(new QcadooUser(user)); } return qcadooUsers; } @Override public Entity getUserEntity(final String userName) { return dataDefinitionService.get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_USER).find() .add(SearchRestrictions.eq(UserFields.USER_NAME, userName)).setMaxResults(1).uniqueResult(); } @Override @Monitorable public Long getCurrentUserId() { String userName = SecurityContextHolder.getContext().getAuthentication().getName(); Entity user = getUserEntity(userName); checkNotNull(user, "Current user with login %s cannot be found", userName); return user.getId(); } @Override @Monitorable public UserDetails loadUserByUsername(final String username) { Entity user = getUserEntity(username); if (user == null) { throw new UsernameNotFoundException("Username " + username + " not found"); } return convertEntityToUserDetails(user); } protected UserDetails convertEntityToUserDetails(final Entity user) { List<GrantedAuthority> grantedAuthorities = Lists.newArrayList(); for (Entity role : user.getBelongsToField(UserFields.GROUP).getManyToManyField(GroupFields.ROLES)) { SecurityRole securityRole = securityRolesService.getRoleByIdentifier(role.getStringField(RoleFields.IDENTIFIER)); checkState(securityRole != null, "Role '%s' not defined", role.getStringField(RoleFields.IDENTIFIER)); grantedAuthorities.add(new GrantedAuthorityImpl(securityRole.getRoleIdentifier())); } checkState(!grantedAuthorities.isEmpty(), "Current user with login %s cannot be found", user.getStringField(UserFields.USER_NAME)); return new User(user.getStringField(UserFields.USER_NAME), user.getStringField(UserFields.PASSWORD), true, true, true, true, grantedAuthorities); } @Override public void createNewToken(final PersistentRememberMeToken persistentRememberMeToken) { Entity persistentToken = dataDefinitionService.get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_PERSISTENT_TOKEN).create(); persistentToken.setField(PersistentTokenFields.USER_NAME, persistentRememberMeToken.getUsername()); persistentToken.setField(PersistentTokenFields.SERIES, persistentRememberMeToken.getSeries()); persistentToken.setField(PersistentTokenFields.TOKEN, persistentRememberMeToken.getTokenValue()); persistentToken.setField(PersistentTokenFields.LAST_USED, persistentRememberMeToken.getDate()); dataDefinitionService.get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_PERSISTENT_TOKEN) .save(persistentToken); } @Override public void updateToken(final String series, final String token, final Date lastUsed) { Entity persistentToken = getPersistentToken(series); if (persistentToken != null) { persistentToken.setField(PersistentTokenFields.TOKEN, token); persistentToken.setField(PersistentTokenFields.LAST_USED, lastUsed); dataDefinitionService.get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_PERSISTENT_TOKEN) .save(persistentToken); } } @Override public PersistentRememberMeToken getTokenForSeries(final String series) { Entity persistentToken = getPersistentToken(series); if ((persistentToken == null) || (getUserEntity(persistentToken.getStringField(PersistentTokenFields.USER_NAME)) == null)) { return null; } return new PersistentRememberMeToken(persistentToken.getStringField(PersistentTokenFields.USER_NAME), persistentToken.getStringField(PersistentTokenFields.SERIES), persistentToken.getStringField(PersistentTokenFields.TOKEN), persistentToken.getDateField(PersistentTokenFields.LAST_USED)); } @Override public void removeUserTokens(final String username) { List<Entity> persistentTokens = dataDefinitionService .get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_PERSISTENT_TOKEN).find() .add(SearchRestrictions.eq(PersistentTokenFields.USER_NAME, username)).list().getEntities(); for (Entity persistentToken : persistentTokens) { dataDefinitionService.get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_PERSISTENT_TOKEN) .delete(persistentToken.getId()); } } private Entity getPersistentToken(final String series) { List<Entity> persistentTokens = dataDefinitionService .get(QcadooSecurityConstants.PLUGIN_IDENTIFIER, QcadooSecurityConstants.MODEL_PERSISTENT_TOKEN).find() .add(SearchRestrictions.eq(PersistentTokenFields.SERIES, series)).list().getEntities(); if (persistentTokens.size() == 1) { return persistentTokens.get(0); } else { return null; } } @Override public boolean hasRole(Entity user, String targetRoleIdetifier) { checkNotNull(targetRoleIdetifier, L_TARGET_ROLE_IDENTIFIER_MUST_BE_GIVEN); checkNotNull(user, L_USER_ENTITY_MUST_BE_GIVEN); List<Entity> roles = user.getBelongsToField(UserFields.GROUP).getManyToManyField(GroupFields.ROLES); for (Entity role : roles) { if (targetRoleIdetifier.equals(role.getStringField(RoleFields.IDENTIFIER))) { return true; } } return false; } @Override public boolean hasCurrentUserRole(String targetRoleIdentifier) { checkNotNull(targetRoleIdentifier, L_TARGET_ROLE_IDENTIFIER_MUST_BE_GIVEN); Entity user = getUserEntity(getCurrentUserName()); List<Entity> roles = user.getBelongsToField(UserFields.GROUP).getManyToManyField(GroupFields.ROLES); for (Entity role : roles) { if (targetRoleIdentifier.equals(role.getStringField(RoleFields.IDENTIFIER))) { return true; } } return false; } }