com.helger.photon.security.usergroup.UserGroupManager Maven / Gradle / Ivy
/*
* Copyright (C) 2014-2023 Philip Helger (www.helger.com)
* philip[at]helger[dot]com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.helger.photon.security.usergroup;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.annotation.ReturnsMutableObject;
import com.helger.commons.callback.CallbackList;
import com.helger.commons.collection.impl.CommonsArrayList;
import com.helger.commons.collection.impl.ICommonsList;
import com.helger.commons.state.EChange;
import com.helger.commons.string.StringHelper;
import com.helger.dao.DAOException;
import com.helger.photon.audit.AuditHelper;
import com.helger.photon.io.dao.AbstractPhotonMapBasedWALDAO;
import com.helger.photon.security.CSecurity;
import com.helger.photon.security.object.BusinessObjectHelper;
import com.helger.photon.security.object.StubObject;
import com.helger.photon.security.role.IRoleManager;
import com.helger.photon.security.user.IUserManager;
/**
* This class manages the available user groups.
*
* @author Philip Helger
*/
@ThreadSafe
public class UserGroupManager extends AbstractPhotonMapBasedWALDAO implements IUserGroupManager
{
private final IUserManager m_aUserMgr;
private final IRoleManager m_aRoleMgr;
private final CallbackList m_aCallbacks = new CallbackList <> ();
public UserGroupManager (@Nonnull @Nonempty final String sFilename,
@Nonnull final IUserManager aUserMgr,
@Nonnull final IRoleManager aRoleMgr) throws DAOException
{
super (UserGroup.class, sFilename);
m_aUserMgr = ValueEnforcer.notNull (aUserMgr, "UserManager");
m_aRoleMgr = ValueEnforcer.notNull (aRoleMgr, "RoleManager");
}
@Nonnull
public final IUserManager getUserManager ()
{
return m_aUserMgr;
}
@Nonnull
public final IRoleManager getRoleManager ()
{
return m_aRoleMgr;
}
@Nonnull
public static UserGroup createDefaultUserGroupAdministrators ()
{
return new UserGroup (StubObject.createForCurrentUserAndID (CSecurity.USERGROUP_ADMINISTRATORS_ID),
CSecurity.USERGROUP_ADMINISTRATORS_NAME,
(String) null);
}
@Nonnull
public static UserGroup createDefaultUserGroupUsers ()
{
return new UserGroup (StubObject.createForCurrentUserAndID (CSecurity.USERGROUP_USERS_ID),
CSecurity.USERGROUP_USERS_NAME,
(String) null);
}
@Nonnull
public static UserGroup createDefaultUserGroupGuests ()
{
return new UserGroup (StubObject.createForCurrentUserAndID (CSecurity.USERGROUP_GUESTS_ID),
CSecurity.USERGROUP_GUESTS_NAME,
(String) null);
}
public void createDefaultsForTest ()
{
// Administrators user group
UserGroup aUG = getOfID (CSecurity.USERGROUP_ADMINISTRATORS_ID);
if (aUG == null)
aUG = m_aRWLock.writeLockedGet ( () -> internalCreateItem (createDefaultUserGroupAdministrators ()));
if (m_aUserMgr.containsWithID (CSecurity.USER_ADMINISTRATOR_ID))
aUG.assignUser (CSecurity.USER_ADMINISTRATOR_ID);
if (m_aRoleMgr.containsWithID (CSecurity.ROLE_ADMINISTRATOR_ID))
aUG.assignRole (CSecurity.ROLE_ADMINISTRATOR_ID);
// Users user group
aUG = getOfID (CSecurity.USERGROUP_USERS_ID);
if (aUG == null)
aUG = m_aRWLock.writeLockedGet ( () -> internalCreateItem (createDefaultUserGroupUsers ()));
if (m_aUserMgr.containsWithID (CSecurity.USER_USER_ID))
aUG.assignUser (CSecurity.USER_USER_ID);
if (m_aRoleMgr.containsWithID (CSecurity.ROLE_USER_ID))
aUG.assignRole (CSecurity.ROLE_USER_ID);
// Guests user group
aUG = getOfID (CSecurity.USERGROUP_GUESTS_ID);
if (aUG == null)
aUG = m_aRWLock.writeLockedGet ( () -> internalCreateItem (createDefaultUserGroupGuests ()));
if (m_aUserMgr.containsWithID (CSecurity.USER_GUEST_ID))
aUG.assignUser (CSecurity.USER_GUEST_ID);
// no role for this user group
}
@Nonnull
@ReturnsMutableObject
public CallbackList userGroupModificationCallbacks ()
{
return m_aCallbacks;
}
@Nonnull
public IUserGroup createNewUserGroup (@Nonnull @Nonempty final String sName,
@Nullable final String sDescription,
@Nullable final Map aCustomAttrs)
{
// Create user group
final UserGroup aUserGroup = new UserGroup (sName, sDescription, aCustomAttrs);
// Store
m_aRWLock.writeLocked ( () -> internalCreateItem (aUserGroup));
AuditHelper.onAuditCreateSuccess (UserGroup.OT, aUserGroup.getID (), sName, sDescription, aCustomAttrs);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupCreated (aUserGroup, false));
return aUserGroup;
}
@Nonnull
public IUserGroup createPredefinedUserGroup (@Nonnull @Nonempty final String sID,
@Nonnull @Nonempty final String sName,
@Nullable final String sDescription,
@Nullable final Map aCustomAttrs)
{
// Create user group
final UserGroup aUserGroup = new UserGroup (StubObject.createForCurrentUserAndID (sID, aCustomAttrs), sName, sDescription);
// Store
m_aRWLock.writeLocked ( () -> internalCreateItem (aUserGroup));
AuditHelper.onAuditCreateSuccess (UserGroup.OT, aUserGroup.getID (), "predefined-usergroup", sName, sDescription, aCustomAttrs);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupCreated (aUserGroup, true));
return aUserGroup;
}
@Nonnull
public EChange deleteUserGroup (@Nullable final String sUserGroupID)
{
if (StringHelper.hasNoText (sUserGroupID))
return EChange.UNCHANGED;
final UserGroup aDeletedUserGroup = getOfID (sUserGroupID);
if (aDeletedUserGroup == null)
{
AuditHelper.onAuditDeleteFailure (UserGroup.OT, sUserGroupID, "no-such-id");
return EChange.UNCHANGED;
}
m_aRWLock.writeLock ().lock ();
try
{
if (BusinessObjectHelper.setDeletionNow (aDeletedUserGroup).isUnchanged ())
{
AuditHelper.onAuditDeleteFailure (UserGroup.OT, sUserGroupID, "already-deleted");
return EChange.UNCHANGED;
}
internalMarkItemDeleted (aDeletedUserGroup);
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditDeleteSuccess (UserGroup.OT, sUserGroupID);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupDeleted (sUserGroupID));
return EChange.CHANGED;
}
@Nonnull
public EChange undeleteUserGroup (@Nullable final String sUserGroupID)
{
final UserGroup aUserGroup = getOfID (sUserGroupID);
if (aUserGroup == null)
{
AuditHelper.onAuditUndeleteFailure (UserGroup.OT, sUserGroupID, "no-such-id");
return EChange.UNCHANGED;
}
m_aRWLock.writeLock ().lock ();
try
{
if (BusinessObjectHelper.setUndeletionNow (aUserGroup).isUnchanged ())
{
AuditHelper.onAuditUndeleteFailure (UserGroup.OT, sUserGroupID, "not-deleted");
return EChange.UNCHANGED;
}
internalMarkItemUndeleted (aUserGroup);
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditUndeleteSuccess (UserGroup.OT, sUserGroupID);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupUndeleted (sUserGroupID));
return EChange.CHANGED;
}
@Nullable
public IUserGroup getUserGroupOfID (@Nullable final String sUserGroupID)
{
return getOfID (sUserGroupID);
}
@Nonnull
@ReturnsMutableCopy
public ICommonsList getAllActiveUserGroups ()
{
return getAll (x -> !x.isDeleted ());
}
@Nonnull
@ReturnsMutableCopy
public ICommonsList getAllDeletedUserGroups ()
{
return getAll (IUserGroup::isDeleted);
}
@Nonnull
public EChange renameUserGroup (@Nullable final String sUserGroupID, @Nonnull @Nonempty final String sNewName)
{
// Resolve user group
final UserGroup aUserGroup = getOfID (sUserGroupID);
if (aUserGroup == null)
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "set-name", sUserGroupID, "no-such-id");
return EChange.UNCHANGED;
}
m_aRWLock.writeLock ().lock ();
try
{
if (aUserGroup.setName (sNewName).isUnchanged ())
return EChange.UNCHANGED;
BusinessObjectHelper.setLastModificationNow (aUserGroup);
internalUpdateItem (aUserGroup);
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditModifySuccess (UserGroup.OT, "set-name", sUserGroupID, sNewName);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupRenamed (sUserGroupID));
return EChange.CHANGED;
}
@Nonnull
public EChange setUserGroupData (@Nullable final String sUserGroupID,
@Nonnull @Nonempty final String sNewName,
@Nullable final String sNewDescription,
@Nullable final Map aNewCustomAttrs)
{
// Resolve user group
final UserGroup aUserGroup = getOfID (sUserGroupID);
if (aUserGroup == null)
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "set-all", sUserGroupID, "no-such-id");
return EChange.UNCHANGED;
}
m_aRWLock.writeLock ().lock ();
try
{
EChange eChange = aUserGroup.setName (sNewName);
eChange = eChange.or (aUserGroup.setDescription (sNewDescription));
eChange = eChange.or (aUserGroup.attrs ().setAll (aNewCustomAttrs));
if (eChange.isUnchanged ())
return EChange.UNCHANGED;
BusinessObjectHelper.setLastModificationNow (aUserGroup);
internalUpdateItem (aUserGroup);
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditModifySuccess (UserGroup.OT, "set-all", aUserGroup.getID (), sNewName, sNewDescription, aNewCustomAttrs);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupUpdated (sUserGroupID));
return EChange.CHANGED;
}
@Nonnull
public EChange assignUserToUserGroup (@Nullable final String sUserGroupID, @Nonnull @Nonempty final String sUserID)
{
ValueEnforcer.notEmpty (sUserID, "UserID");
if (StringHelper.hasNoText (sUserGroupID))
return EChange.UNCHANGED;
// Resolve user group
final UserGroup aUserGroup = getOfID (sUserGroupID);
if (aUserGroup == null)
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "assign-user", sUserGroupID, sUserID, "no-such-id");
return EChange.UNCHANGED;
}
m_aRWLock.writeLock ().lock ();
try
{
if (aUserGroup.assignUser (sUserID).isUnchanged ())
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "assign-user", sUserGroupID, sUserID, "already-assigned");
return EChange.UNCHANGED;
}
BusinessObjectHelper.setLastModificationNow (aUserGroup);
internalUpdateItem (aUserGroup);
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditModifySuccess (UserGroup.OT, "assign-user", sUserGroupID, sUserID);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupUserAssignment (sUserGroupID, sUserID, true));
return EChange.CHANGED;
}
@Nonnull
public EChange unassignUserFromUserGroup (@Nullable final String sUserGroupID, @Nullable final String sUserID)
{
if (StringHelper.hasNoText (sUserGroupID))
return EChange.UNCHANGED;
if (StringHelper.hasNoText (sUserID))
return EChange.UNCHANGED;
// Resolve user group
final UserGroup aUserGroup = getOfID (sUserGroupID);
if (aUserGroup == null)
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "unassign-user", sUserGroupID, "no-such-id");
return EChange.UNCHANGED;
}
m_aRWLock.writeLock ().lock ();
try
{
if (aUserGroup.unassignUser (sUserID).isUnchanged ())
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "unassign-user", sUserGroupID, sUserID, "not-assigned");
return EChange.UNCHANGED;
}
BusinessObjectHelper.setLastModificationNow (aUserGroup);
internalUpdateItem (aUserGroup);
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditModifySuccess (UserGroup.OT, "unassign-user", sUserGroupID, sUserID);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupUserAssignment (sUserGroupID, sUserID, false));
return EChange.CHANGED;
}
@Nonnull
public EChange unassignUserFromAllUserGroups (@Nullable final String sUserID)
{
if (StringHelper.hasNoText (sUserID))
return EChange.UNCHANGED;
final ICommonsList aAffectedUserGroups = new CommonsArrayList <> ();
m_aRWLock.writeLock ().lock ();
try
{
EChange eChange = EChange.UNCHANGED;
for (final UserGroup aUserGroup : internalDirectGetAll ())
if (aUserGroup.unassignUser (sUserID).isChanged ())
{
aAffectedUserGroups.add (aUserGroup);
BusinessObjectHelper.setLastModificationNow (aUserGroup);
internalUpdateItem (aUserGroup);
eChange = EChange.CHANGED;
}
if (eChange.isUnchanged ())
return EChange.UNCHANGED;
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditModifySuccess (UserGroup.OT, "unassign-user-from-all-usergroups", sUserID);
// Execute callback as the very last action
for (final IUserGroup aUserGroup : aAffectedUserGroups)
m_aCallbacks.forEach (aCB -> aCB.onUserGroupUserAssignment (aUserGroup.getID (), sUserID, false));
return EChange.CHANGED;
}
@Nonnull
@ReturnsMutableCopy
public ICommonsList getAllUserGroupsWithAssignedUser (@Nullable final String sUserID)
{
if (StringHelper.hasNoText (sUserID))
return new CommonsArrayList <> ();
return getAll (aUserGroup -> aUserGroup.containsUserID (sUserID));
}
@Nonnull
@ReturnsMutableCopy
public ICommonsList getAllUserGroupIDsWithAssignedUser (@Nullable final String sUserID)
{
if (StringHelper.hasNoText (sUserID))
return new CommonsArrayList <> ();
return getAllMapped (aUserGroup -> aUserGroup.containsUserID (sUserID), IUserGroup::getID);
}
@Nonnull
public EChange assignRoleToUserGroup (@Nullable final String sUserGroupID, @Nonnull @Nonempty final String sRoleID)
{
ValueEnforcer.notEmpty (sRoleID, "RoleID");
if (StringHelper.hasNoText (sUserGroupID))
return EChange.UNCHANGED;
// Resolve user group
final UserGroup aUserGroup = getOfID (sUserGroupID);
if (aUserGroup == null)
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "assign-role", sUserGroupID, "no-such-id");
return EChange.UNCHANGED;
}
m_aRWLock.writeLock ().lock ();
try
{
if (aUserGroup.assignRole (sRoleID).isUnchanged ())
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "assign-role", sUserGroupID, sRoleID, "already-assigned");
return EChange.UNCHANGED;
}
BusinessObjectHelper.setLastModificationNow (aUserGroup);
internalUpdateItem (aUserGroup);
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditModifySuccess (UserGroup.OT, "assign-role", sUserGroupID, sRoleID);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupRoleAssignment (sUserGroupID, sRoleID, true));
return EChange.CHANGED;
}
@Nonnull
public EChange unassignRoleFromUserGroup (@Nullable final String sUserGroupID, @Nullable final String sRoleID)
{
if (StringHelper.hasNoText (sUserGroupID))
return EChange.UNCHANGED;
if (StringHelper.hasNoText (sRoleID))
return EChange.UNCHANGED;
// Resolve user group
final UserGroup aUserGroup = getOfID (sUserGroupID);
if (aUserGroup == null)
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "unassign-role", sUserGroupID, "no-such-id");
return EChange.UNCHANGED;
}
m_aRWLock.writeLock ().lock ();
try
{
if (aUserGroup.unassignRole (sRoleID).isUnchanged ())
{
AuditHelper.onAuditModifyFailure (UserGroup.OT, "unassign-role", sUserGroupID, sRoleID, "not-assigned");
return EChange.UNCHANGED;
}
BusinessObjectHelper.setLastModificationNow (aUserGroup);
internalUpdateItem (aUserGroup);
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditModifySuccess (UserGroup.OT, "unassign-role", sUserGroupID, sRoleID);
// Execute callback as the very last action
m_aCallbacks.forEach (aCB -> aCB.onUserGroupRoleAssignment (sUserGroupID, sRoleID, false));
return EChange.CHANGED;
}
@Nonnull
public EChange unassignRoleFromAllUserGroups (@Nullable final String sRoleID)
{
if (StringHelper.hasNoText (sRoleID))
return EChange.UNCHANGED;
final ICommonsList aAffectedUserGroups = new CommonsArrayList <> ();
m_aRWLock.writeLock ().lock ();
try
{
EChange eChange = EChange.UNCHANGED;
for (final UserGroup aUserGroup : internalDirectGetAll ())
if (aUserGroup.unassignRole (sRoleID).isChanged ())
{
aAffectedUserGroups.add (aUserGroup);
BusinessObjectHelper.setLastModificationNow (aUserGroup);
internalUpdateItem (aUserGroup);
eChange = EChange.CHANGED;
}
if (eChange.isUnchanged ())
return EChange.UNCHANGED;
}
finally
{
m_aRWLock.writeLock ().unlock ();
}
AuditHelper.onAuditModifySuccess (UserGroup.OT, "unassign-role-from-all-usergroups", sRoleID);
// Execute callback as the very last action
for (final IUserGroup aUserGroup : aAffectedUserGroups)
m_aCallbacks.forEach (aCB -> aCB.onUserGroupRoleAssignment (aUserGroup.getID (), sRoleID, false));
return EChange.CHANGED;
}
@Nonnull
@ReturnsMutableCopy
public ICommonsList getAllUserGroupsWithAssignedRole (@Nullable final String sRoleID)
{
if (StringHelper.hasNoText (sRoleID))
return getNone ();
return getAll (aUserGroup -> aUserGroup.containsRoleID (sRoleID));
}
@Nonnull
@ReturnsMutableCopy
public ICommonsList getAllUserGroupIDsWithAssignedRole (@Nullable final String sRoleID)
{
if (StringHelper.hasNoText (sRoleID))
return getNone ();
return getAllMapped (aUserGroup -> aUserGroup.containsRoleID (sRoleID), IUserGroup::getID);
}
public boolean containsUserGroupWithAssignedRole (@Nullable final String sRoleID)
{
return containsAny (aUserGroup -> aUserGroup.containsRoleID (sRoleID));
}
public boolean containsAnyUserGroupWithAssignedUserAndRole (@Nullable final String sUserID, @Nullable final String sRoleID)
{
if (StringHelper.hasNoText (sUserID))
return false;
if (StringHelper.hasNoText (sRoleID))
return false;
return containsAny (aUserGroup -> aUserGroup.containsUserID (sUserID) && aUserGroup.containsRoleID (sRoleID));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy