blob: 1ca7f47940be7e838b5b8c5d399615aa0543632c [file] [log] [blame]
package org.apache.archiva.redback.users.jpa;
/*
* 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.
*/
import org.apache.archiva.redback.policy.UserSecurityPolicy;
import org.apache.archiva.redback.users.AbstractUserManager;
import org.apache.archiva.redback.users.Messages;
import org.apache.archiva.redback.users.PermanentUserException;
import org.apache.archiva.redback.users.User;
import org.apache.archiva.redback.users.UserManagerException;
import org.apache.archiva.redback.users.UserNotFoundException;
import org.apache.archiva.redback.users.UserQuery;
import org.apache.archiva.redback.users.jpa.model.JpaUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.transaction.Transactional;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Created by martin on 20.09.16.
*/
@Service("userManager#jpa")
public class JpaUserManager extends AbstractUserManager {
@PersistenceContext(unitName = "redback-jpa")
EntityManager em;
@Inject
private UserSecurityPolicy userSecurityPolicy;
// JpaUserManager is a singleton and initialization should be thread safe
private AtomicBoolean initialized = new AtomicBoolean(false);
public void setEntityManager(EntityManager em) {
this.em = em;
}
@Override
public boolean isReadOnly() {
return false;
}
@Override
public String getId() {
return "jpa";
}
private EntityManager getEm() {
if (initialized.compareAndSet(false,true)) {
Query q = em.createQuery("SELECT COUNT(u.username) FROM JpaUser u");
boolean dbInit = q.getFirstResult()==0;
fireUserManagerInit(dbInit);
}
return em;
}
@Override
public User createUser(String username, String fullName, String emailAddress) throws UserManagerException {
JpaUser user = new JpaUser();
user.setUsername(username);
user.setFullName(fullName);
user.setEmail(emailAddress);
return user;
}
@Override
public UserQuery createUserQuery() {
return new JpaUserQuery();
}
@Override
public List<? extends User> getUsers() throws UserManagerException {
final EntityManager em = getEm();
TypedQuery<JpaUser> q= em.createQuery("SELECT x from JpaUser x", JpaUser.class);
return q.getResultList();
}
@Override
public List<? extends User> getUsers(boolean orderAscending) throws UserManagerException {
final EntityManager em = getEm();
final String orderFlag = orderAscending ? "ASC" : "DESC";
TypedQuery<JpaUser> q = em.createQuery("SELECT u FROM JpaUser u ORDER BY u.username "+orderFlag, JpaUser.class);
return q.getResultList();
}
@Transactional
@Override
public User addUser(User user) throws UserManagerException {
EntityManager em = getEm();
if ( !( user instanceof JpaUser ) )
{
throw new UserManagerException( "Unable to Add User. User object " + user.getClass().getName() +
" is not an instance of " + JpaUser.class.getName() );
}
if ( StringUtils.isEmpty( user.getUsername() ) )
{
throw new IllegalStateException(
Messages.getString( "user.manager.cannot.add.user.without.username" ) ); //$NON-NLS-1$
}
userSecurityPolicy.extensionChangePassword( user );
fireUserManagerUserAdded( user );
// TODO: find a better solution
// workaround for avoiding the admin from providing another password on the next login after the
// admin account has been created
// extensionChangePassword by default sets the password change status to false
if ( "admin".equals( user.getUsername() ) )
{
user.setPasswordChangeRequired( false );
}
else
{
user.setPasswordChangeRequired( true );
}
if (user.getLastPasswordChange()==null) {
user.setLastPasswordChange(new Date());
}
em.persist( user );
return user;
}
@Transactional
@Override
public User updateUser(User user) throws UserManagerException {
return updateUser(user, false);
}
@Override
public User findUser(String username) throws UserManagerException {
if (username==null) {
throw new UserNotFoundException("Username was <null>");
}
final EntityManager em = getEm();
TypedQuery<JpaUser> q = em.createQuery("SELECT u FROM JpaUser u WHERE LOWER(u.username)=:uname", JpaUser.class);
q.setParameter("uname",username.toLowerCase());
User result;
try {
result = q.getSingleResult();
} catch (NoResultException ex ) {
throw new UserNotFoundException(ex);
}
return result;
}
@Override
public User findUser(String username, boolean useCache) throws UserManagerException {
return findUser(username);
}
@Override
public List<? extends User> findUsersByUsernameKey(String usernameKey, boolean orderAscending) throws UserManagerException {
return findUsers("username",usernameKey,"username",orderAscending);
}
@Override
public List<? extends User> findUsersByFullNameKey(String fullNameKey, boolean orderAscending) throws UserManagerException {
return findUsers("fullName",fullNameKey,"username",orderAscending);
}
@Override
public List<? extends User> findUsersByEmailKey(String emailKey, boolean orderAscending) throws UserManagerException {
return findUsers("email",emailKey,"username", orderAscending);
}
@Override
public List<? extends User> findUsersByQuery(final UserQuery queryParam) throws UserManagerException {
final EntityManager em = getEm();
final JpaUserQuery query = (JpaUserQuery)queryParam;
String orderByAttribute;
if (UserQuery.ORDER_BY_EMAIL.equals(query.getOrderBy())) {
orderByAttribute="email";
} else if (UserQuery.ORDER_BY_FULLNAME.equals(query.getOrderBy())) {
orderByAttribute="fullName";
} else if (UserQuery.ORDER_BY_USERNAME.equals(query.getOrderBy())) {
orderByAttribute="username";
} else {
throw new IllegalArgumentException("Unknown order attribute "+query.getOrderBy());
}
StringBuilder sb = new StringBuilder("SELECT u FROM JpaUser u ");
if (query.hasUsername()||query.hasFullName()||query.hasEmail()) {
sb.append("WHERE ");
}
boolean checkBefore = false;
if (query.hasUsername()) {
sb.append("LOWER(u.username) LIKE :username ");
checkBefore=true;
}
if (query.hasEmail()) {
if (checkBefore) {
sb.append("AND ");
}
checkBefore=true;
sb.append("LOWER(u.email) LIKE :email ");
}
if (query.hasFullName()) {
if (checkBefore) {
sb.append("AND ");
}
sb.append("LOWER(u.fullName) LIKE :fullname ");
}
if (query.getOrderBy()!=null && !"".equals(query.getOrderBy())) {
sb.append("ORDER BY u.").append(orderByAttribute).append(query.isAscending() ? " ASC" : " DESC");
}
TypedQuery<User> q = em.createQuery(sb.toString(), User.class);
if (query.hasUsername()) {
q.setParameter("username", "%"+query.getUsername().toLowerCase()+"%");
}
if (query.hasEmail()) {
q.setParameter("email", "%"+query.getEmail().toLowerCase()+"%");
}
if (query.hasFullName()) {
q.setParameter("fullname", "%"+query.getFullName().toLowerCase()+"%");
}
q.setFirstResult((int)query.getFirstResult()).setMaxResults((int)query.getMaxResults());
return q.getResultList();
}
private List<? extends User> findUsers(final String attribute, final String pattern,
final String orderAttribute, final boolean orderAscending) {
final EntityManager em = getEm();
StringBuilder sb = new StringBuilder("SELECT u FROM JpaUser u WHERE LOWER(u.");
sb.append(attribute).append(") LIKE :patternvalue ORDER BY u.").append(orderAttribute);
sb.append(orderAscending ? " ASC" : " DESC");
TypedQuery<User> q = em.createQuery(sb.toString(),User.class);
q.setParameter("patternvalue","%"+pattern.toLowerCase()+"%");
return q.getResultList();
}
@Override
public boolean userExists(String principal) throws UserManagerException {
EntityManager em = getEm();
JpaUser user = em.find(JpaUser.class, principal);
return user != null;
}
@Transactional
@Override
public void deleteUser(String username) throws UserManagerException {
final EntityManager em = getEm();
User u = findUser(username);
if (u.isPermanent()) {
throw new PermanentUserException("User "+username+" cannot be deleted");
}
em.remove(u);
fireUserManagerUserRemoved(u);
}
@Transactional
@Override
public void addUserUnchecked(User user) throws UserManagerException {
log.info("addUserUnchecked "+user.getUsername());
if ( !( user instanceof JpaUser ) )
{
throw new UserManagerException( "Unable to Add User. User object " + user.getClass().getName() +
" is not an instance of " + JpaUser.class.getName() );
}
if ( StringUtils.isEmpty( user.getUsername() ) )
{
throw new IllegalStateException(
Messages.getString( "user.manager.cannot.add.user.without.username" ) ); //$NON-NLS-1$
}
TypedQuery<JpaUser> q = em.createQuery("SELECT u FROM JpaUser u", JpaUser.class);
for (JpaUser u : q.getResultList()) {
log.info("USER FOUND: "+u.getUsername());
}
log.info("NEW USER "+user.getUsername());
em.persist( user );
}
@Transactional
@Override
public void eraseDatabase() {
EntityManager em = getEm();
TypedQuery<JpaUser> q = em.createQuery("SELECT u FROM JpaUser u", JpaUser.class);
for (JpaUser u : q.getResultList()) {
u.getPreviousEncodedPasswords().clear();
}
em.flush();
Query qd = em.createQuery("DELETE FROM JpaUser u");
qd.executeUpdate();
em.clear();
}
@Transactional
@Override
public User updateUser(User user, boolean passwordChangeRequired) throws UserManagerException {
if ( !( user instanceof JpaUser ) )
{
throw new UserManagerException( "Unable to update user. User object " + user.getClass().getName() +
" is not an instance of " + JpaUser.class.getName() );
}
if ( StringUtils.isNotEmpty( user.getPassword() ) )
{
userSecurityPolicy.extensionChangePassword( user, passwordChangeRequired );
}
JpaUser jpaUser = (JpaUser) user;
final EntityManager em = getEm();
jpaUser = em.merge(jpaUser);
fireUserManagerUserUpdated(jpaUser);
return jpaUser;
}
@Override
public String getDescriptionKey() {
return "archiva.redback.usermanager.jpa";
}
@Override
public boolean isFinalImplementation() {
return true;
}
// Override to add transactional annotation
@Transactional
@Override
public User createGuestUser() throws UserManagerException {
return super.createGuestUser();
}
}