Class ActorService
- All Implemented Interfaces:
org.springframework.security.core.userdetails.UserDetailsService
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final @NonNull ActorMapperCreatesActorobjects from data-transfer objects representing Actors created by administrators (ActorAuthority.IT_ADMINISTRATION,ActorAuthority.FACULTY_ADMINISTRATION).private final @NonNull ActorMetadataRepositoryProvides database access to modify theActorMetadata.private final @NonNull ActorRepositoryProvides database access to actually create, modify and delete Actors.private @NonNull StringTheActor.password()of the default administrator.private @NonNull StringTheActor.userNameof the default administrator.These domains are explicitly not permitted as part of the Actors' e-mail addresses.If this List is not empty, only these domains are permitted in the Actors' e-mail addresses.private final @NonNull Durationprivate final @NonNull org.springframework.context.ApplicationEventPublisherUsed to publish certain events likeActorCreatedEvent.private @Nullable org.springframework.security.ldap.authentication.LdapAuthenticationProviderUsed to authenticate users against an LDAP server.private final @Nullable org.springframework.security.ldap.authentication.BindAuthenticatorUsed to authenticate users against an LDAP server.private final @NonNull org.springframework.security.crypto.password.PasswordEncoderprivate final @NonNull RegistrationModeWhether and which registrations are configured to be permitted.private final @NonNull ReservationServiceUsed bydeleteActor(String)to find Reservations of the user to be deleted.private final @NonNull VerificationTokenRepositoryProvides database access to save and retrieve VerificationTokens.private final @NonNull Duration -
Constructor Summary
ConstructorsConstructorDescriptionActorService(@NonNull ActorRepository actorRepository, @NonNull ActorMetadataRepository actorMetadataRepository, @NonNull VerificationTokenRepository verificationTokenRepository, @NonNull ActorMapper actorMapper, @NonNull org.springframework.security.crypto.password.PasswordEncoder passwordEncoder, @NonNull ReservationService reservationService, @Nullable org.springframework.security.ldap.authentication.BindAuthenticator bindAuthenticator, @NonNull RegistrationMode registrationMode, @NonNull Duration verificationTokenValidity, @NonNull Duration eMailVerificationTokenValidity, @NonNull List<String> eMailDomainWhitelist, @NonNull List<String> eMailDomainBlacklist, @NonNull org.springframework.context.ApplicationEventPublisher eventPublisher) -
Method Summary
Modifier and TypeMethodDescriptionvoidchangeEMailAddress(@NonNull String newEMailAddress) Stores a newEMailVerificationTokenwith the givenEMailVerificationToken.eMailAddressin the database, in order to allow anActorto change theirActor.eMailAddressby opening a confirmation link that will be sent by e-mail.voidchangeName(@NonNull String newName) Updates theActor.nameof the current user.voidchangePassword(@NonNull ChangePasswordDTO changePasswordDTO) Sets theActor.password()of theCurrentAuthorityService.getActor()(who must be aLocalActor) to hash of the givenChangePasswordDTO.newPassword.voidchangeUserName(@NonNull String newUserName) Updates theActor.userNameof the current user.@NonNull ActorconfirmNewEMail(@NonNull String verificationToken) Changes theActor.eMailAddressof theVerificationToken.actorto the newEMailVerificationToken.eMailAddress.@NonNull ActorcreateActor(@NonNull LocalActorCreatedByAdminDTO dto) Saves a newActorto the database.voiddeleteActor(@NonNull String userName) Removes theActorwith the givenActor.userNamefrom the database.@NonNull ActorenableAccount(@NonNull String verificationToken) SetsActor.enabledto true for theVerificationToken.actorbelonging to the givenVerificationToken.token.@NonNull org.springframework.data.domain.Page<Actor> findAll(@NonNull org.springframework.data.domain.Pageable pageable) A subset of all Actors in the database table according to the givenPageable.@NonNull ActorfindUserByUserName(@NonNull String userName) private @NonNull VerificationTokengenerateVerificationToken(@NonNull Actor actor) Generates a newVerificationTokenwith theverificationTokenValidityfor the givenActorand saves the former to the database.voidCreates an administratorActorfrom thedefaultUserNameanddefaultPasswordand saves the new administrator to the database, after the application has started.voidIf theldapAuthenticatorhas been set up, initialises theldapAuthenticationProviderwith it.private booleanisValidAndAllowedEmail(@NonNull String eMailAddress) Verifies that the given e-mail address is syntactically valid and that simultaneously@NonNull org.springframework.security.core.userdetails.UserDetailsloadUserByUsername(@NonNull String username) Do not use this method! It is meant only for the Spring framework!voidonLogin(@NonNull org.springframework.security.authentication.event.AuthenticationSuccessEvent success) voidonRegistration(@NonNull ActorCreatedEvent createdEvent) Saves the registration date of the givenActorCreatedEventto theActorMetadatabelonging to theActorCreatedEvent.actor.voidregister(@NonNull LdapRegistrationActorDTO ldapRegistrationActorDTO) Creates a newActorin the database, according to the givenLdapRegistrationActorDTO.voidregister(@NonNull LocalRegistrationActorDTO localRegistrationActorDTO) Creates a newActorin the database, according to the givenLocalRegistrationActorDTO.
-
Field Details
-
defaultUserName
TheActor.userNameof the default administrator. -
defaultPassword
TheActor.password()of the default administrator. -
actorRepository
Provides database access to actually create, modify and delete Actors. -
actorMetadataRepository
Provides database access to modify theActorMetadata. -
verificationTokenRepository
Provides database access to save and retrieve VerificationTokens. -
reservationService
Used bydeleteActor(String)to find Reservations of the user to be deleted. -
passwordEncoder
-
actorMapper
CreatesActorobjects from data-transfer objects representing Actors created by administrators (ActorAuthority.IT_ADMINISTRATION,ActorAuthority.FACULTY_ADMINISTRATION). -
ldapAuthenticator
@Nullable private final @Nullable org.springframework.security.ldap.authentication.BindAuthenticator ldapAuthenticatorUsed to authenticate users against an LDAP server. -
ldapAuthenticationProvider
@Nullable private @Nullable org.springframework.security.ldap.authentication.LdapAuthenticationProvider ldapAuthenticationProviderUsed to authenticate users against an LDAP server. -
registrationMode
Whether and which registrations are configured to be permitted. -
verificationTokenValidity
-
eMailVerificationTokenValidity
-
domainWhitelist
If this List is not empty, only these domains are permitted in the Actors' e-mail addresses. Overrides thedomainBlacklist. -
domainBlacklist
These domains are explicitly not permitted as part of the Actors' e-mail addresses. Less important than thedomainWhitelist. -
eventPublisher
@NonNull private final @NonNull org.springframework.context.ApplicationEventPublisher eventPublisherUsed to publish certain events likeActorCreatedEvent.
-
-
Constructor Details
-
ActorService
public ActorService(@NonNull @NonNull ActorRepository actorRepository, @NonNull @NonNull ActorMetadataRepository actorMetadataRepository, @NonNull @NonNull VerificationTokenRepository verificationTokenRepository, @NonNull @NonNull ActorMapper actorMapper, @NonNull @NonNull org.springframework.security.crypto.password.PasswordEncoder passwordEncoder, @NonNull @NonNull ReservationService reservationService, @Nullable @Nullable org.springframework.security.ldap.authentication.BindAuthenticator bindAuthenticator, @NonNull @NonNull RegistrationMode registrationMode, @NonNull @NonNull Duration verificationTokenValidity, @NonNull @NonNull Duration eMailVerificationTokenValidity, @NonNull @NonNull List<String> eMailDomainWhitelist, @NonNull @NonNull List<String> eMailDomainBlacklist, @NonNull @NonNull org.springframework.context.ApplicationEventPublisher eventPublisher) - Parameters:
actorRepository- TheactorRepositoryto use for database access.actorMetadataRepository- TheactorMetadataRepository.verificationTokenRepository- TheverificationTokenRepository.actorMapper- TheactorMapperused to convert data-transfer objects toActorobjects.passwordEncoder- ThepasswordEncoderused to hash Actors' passwords.reservationService- ThereservationService.bindAuthenticator- TheldapAuthenticator.registrationMode- TheregistrationMode.verificationTokenValidity- TheverificationTokenValidity.eMailVerificationTokenValidity- TheeMailVerificationTokenValidity.eMailDomainWhitelist- ThedomainWhitelist.eMailDomainBlacklist- ThedomainBlacklist.eventPublisher- TheeventPublisher.
-
-
Method Details
-
initialise
@PostConstruct public void initialise()Creates an administratorActorfrom thedefaultUserNameanddefaultPasswordand saves the new administrator to the database, after the application has started. -
initialiseLdap
@PostConstruct public void initialiseLdap()If theldapAuthenticatorhas been set up, initialises theldapAuthenticationProviderwith it. -
generateVerificationToken
@NonNull private @NonNull VerificationToken generateVerificationToken(@NonNull @NonNull Actor actor) Generates a new
VerificationTokenwith theverificationTokenValidityfor the givenActorand saves the former to the database.Does not check whether the
Actor.isEnabled().- Parameters:
actor- TheVerificationToken.actor.- Returns:
- The VerificationToken that was generated.
-
isValidAndAllowedEmail
Verifies that the given e-mail address is syntactically valid and that simultaneously
- it is listed in the
domainWhitelistor - the
domainWhitelistis empty and the e-mail address is not listed in thedomainBlacklist.
- Parameters:
eMailAddress- The e-mail address that shall be checked.- Returns:
- True if the e-mail is valid and allowed, false if it is invalid or banned.
- it is listed in the
-
findAll
@PreAuthorize("hasRole('FACULTY_ADMINISTRATION')") @NonNull public @NonNull org.springframework.data.domain.Page<Actor> findAll(@NonNull @NonNull org.springframework.data.domain.Pageable pageable) A subset of all Actors in the database table according to the givenPageable.- Parameters:
pageable- The pagination information specifying which page of Actors shall be returned.- Returns:
- All actors, but only the specified subset.
- See Also:
-
findUserByUserName
@NonNull public @NonNull Actor findUserByUserName(@NonNull @NonNull String userName) throws NotFoundException - Parameters:
userName- The user name whose corresponding Actor shall be returned.- Returns:
- The Actor associated with the given user name.
- Throws:
NotFoundException- If no Actor with the given user name exists.- Implementation Note:
- There is no @
PreAuthorizehere because it would impair the LDAP login process, because it needs to tell the LDAP library who the authenticated user is. Since the user is not authenticated at that point yet, this method would fail. (We trust the LDAP server not to allow people to impersonate other users.)
-
loadUserByUsername
@NonNull public @NonNull org.springframework.security.core.userdetails.UserDetails loadUserByUsername(@NonNull @NonNull String username) throws org.springframework.security.core.userdetails.UsernameNotFoundException, NoSuchLocalUserException Do not use this method! It is meant only for the Spring framework!- Specified by:
loadUserByUsernamein interfaceorg.springframework.security.core.userdetails.UserDetailsService- Throws:
org.springframework.security.core.userdetails.UsernameNotFoundException- AnActorwith the givenActor.userNamedoes exist, but they do not have set anActor.password(), so that the Actor cannot be used for authentication by theDaoAuthenticationProvider.NoSuchLocalUserException- No Actor with the given user name exists, so that noAuthenticationProvidercan authenticate the current request. (ProviderManagerwill stop attempting authentication if anAccountStatusExceptionis thrown by an AuthenticationProvider.)
-
createActor
@NonNull public @NonNull Actor createActor(@NonNull @NonNull LocalActorCreatedByAdminDTO dto) throws UnauthorisedException, PasswordNotConfirmedException, AlreadyExistsException, de.gustavblass.commons.exceptions.IllegalArgumentException Saves a new
Actorto the database.The Actor on whose behalf this method is called must have sufficient privilege to create Actors with the
ActorRolethat the given data-transfer object has.Generates a new
VerificationTokenfor the Actor and publishes a newActorCreatedEvent. Will be anUnconfirmedRegistrationEventif the account is not enabled.Warning!
This method clears the given data-transfer object in case of success! Then, it will be stripped of all data for security reasons and become useless!
The password will, of course, be hashed before saving it to the database.
- Parameters:
dto- The data-transfer object sent to the server by a client, based on which a new Actor shall be stored in the database. No Actor must exist with the DTO's user name in the database. If the create operation succeeds, this DTO will be cleared of all data!- Returns:
- The Actor that was newly created based on the given DTO.
- Throws:
PasswordNotConfirmedException- If theLocalActorCreatedByAdminDTO.repeatedPassworddoes not match theLocalActorCreatedByAdminDTO.password.UnauthorisedException- If end user making the request is not permitted to create Actors with the ActorRole that the given DTO has. (Includes the case that the end user is not permitted to create end users at all.)AlreadyExistsException- If an Actor with the DTO's user name is already present in the database.de.gustavblass.commons.exceptions.IllegalArgumentException- If noLocalActorCreatedByAdminDTO.passwordis set.
-
deleteActor
@PreAuthorize("hasRole('FACULTY_ADMINISTRATION')") public void deleteActor(@NonNull @NonNull String userName) throws NotFoundException, ActorStillHasReservationsException, UnauthorisedException Removes the
Actorwith the givenActor.userNamefrom the database.The Actor on whose behalf this method is called must have sufficient privilege to delete Actors with the
ActorRolethat the Actor concerned has.The Actor to be deleted must not still have active Reservations that begin or end after the current time.
- Parameters:
userName- The user name of the user that shall no longer be present in the system.- Throws:
NotFoundException- If there is no Actor with the given user name.UnauthorisedException- If end user making the request is not permitted to delete Actors with the ActorRole that the Actor concerned has.ActorStillHasReservationsException- If the Actor still has Reservations.
-
register
public void register(@NonNull @NonNull LocalRegistrationActorDTO localRegistrationActorDTO) throws AlreadyExistsException, PasswordNotConfirmedException, IllegalStateException, InvalidOrBannedEMailAddressException Creates a newActorin the database, according to the givenLocalRegistrationActorDTO. Generates a newVerificationTokenfor the Actor and publishes a newUnconfirmedRegistrationEvent.- Parameters:
localRegistrationActorDTO- The new user.- Throws:
PasswordNotConfirmedException- If theLocalActorCreatedByAdminDTO.repeatedPassworddoes not match theLocalActorCreatedByAdminDTO.password.AlreadyExistsException- If theActorCreatedByAdminDTO.userNamealready exists in the database.InvalidOrBannedEMailAddressException- If theActorCreatedByAdminDTO.eMailAddressis invalid or banned.IllegalStateException- If local registrations are disabled.- Implementation Note:
- This method takes a DTO and not a proper object, because this is the easiest way to validate that the two passwords entered match each other.
-
register
public void register(@NonNull @NonNull LdapRegistrationActorDTO ldapRegistrationActorDTO) throws IllegalStateException, AlreadyExistsException, de.gustavblass.commons.exceptions.IllegalArgumentException Creates a newActorin the database, according to the givenLdapRegistrationActorDTO. TheLdapRegistrationActorDTO.passwordis not stored in the database; it will be verified against an LDAP server during every login process.- Parameters:
ldapRegistrationActorDTO- The new Actor. Must exist at the LDAP server configured in theldapAuthenticationProvider. TheActor.userNamemust not be taken already.- Throws:
IllegalStateException- If LDAP is not configured. SeeinitialiseLdap().AlreadyExistsException- If the user name is already taken.de.gustavblass.commons.exceptions.IllegalArgumentException- If the login credentials are invalid.
-
enableAccount
@NonNull public @NonNull Actor enableAccount(@NonNull @NonNull String verificationToken) throws NotFoundException, ExpiredException, AccountIsLockedException SetsActor.enabledto true for theVerificationToken.actorbelonging to the givenVerificationToken.token. Deletes theVerificationTokenfrom the database in case of success.- Parameters:
verificationToken- The token through which the Actor confirms their registration.- Returns:
- The
Actorwhose VerificationToken was used. - Throws:
NotFoundException- If the given verification token is not present in the database.ExpiredException- If the verification token exists in the database but has expired.AccountIsLockedException-If the
.invalid reference
Actor#isLocked()
-
changePassword
@PreAuthorize("isAuthenticated()") public void changePassword(@NonNull @NonNull ChangePasswordDTO changePasswordDTO) throws NotLoggedInException, WrongPasswordException, PasswordNotConfirmedException, NotALocalUserException Sets theActor.password()of theCurrentAuthorityService.getActor()(who must be aLocalActor) to hash of the givenChangePasswordDTO.newPassword.- Parameters:
changePasswordDTO- The current and new password.ChangePasswordDTO.currentPasswordmust match the one stored in the database before the change operation.ChangePasswordDTO.newPassword()andChangePasswordDTO.repeatedNewPasswordmust match.- Throws:
NotLoggedInException- If the current end user is not authenticated. Should never happen, thanks to the@PreAuthorizeannotation.WrongPasswordException- If the current password is incorrect.PasswordNotConfirmedException- If the new password was not repeated correctly.NotALocalUserException- If theActoris not aLocalActor.
-
changeUserName
@PreAuthorize("isFullyAuthenticated()") public void changeUserName(@NonNull @NonNull String newUserName) throws de.gustavblass.commons.exceptions.IllegalArgumentException, NotLoggedInException, NotALocalUserException, NoDifferenceException, AlreadyExistsException Updates theActor.userNameof the current user.- Parameters:
newUserName- The new user name that shall replace the old one. Must not be already taken. Must not be blank. Must not match the current one.- Throws:
NotLoggedInException- If the user is not authenticated.NotALocalUserException- If the user is not aLocalActor.NoDifferenceException- If the new user name matches the old one.AlreadyExistsException- If a different Actor already occupies the given new user name.de.gustavblass.commons.exceptions.IllegalArgumentException- If the given new user name is blank.
-
changeName
@PreAuthorize("isFullyAuthenticated()") public void changeName(@NonNull @NonNull String newName) throws de.gustavblass.commons.exceptions.IllegalArgumentException, NotLoggedInException, NotALocalUserException, NoDifferenceException Updates theActor.nameof the current user.- Parameters:
newName- The new name that shall replace the old one. Must not be blank. Must not match the current one.- Throws:
NotLoggedInException- If the user is not authenticated.NotALocalUserException- If the user is not aLocalActor.NoDifferenceException- If the new name matches the old one.de.gustavblass.commons.exceptions.IllegalArgumentException- If the given new name is blank.
-
changeEMailAddress
@PreAuthorize("isFullyAuthenticated()") public void changeEMailAddress(@NonNull @NonNull String newEMailAddress) throws InvalidOrBannedEMailAddressException, NotLoggedInException, NotALocalUserException, NoDifferenceException, AlreadyExistsException Stores a new
EMailVerificationTokenwith the givenEMailVerificationToken.eMailAddressin the database, in order to allow anActorto change theirActor.eMailAddressby opening a confirmation link that will be sent by e-mail.Publishes a new
EMailChangeEventwith the current actor as theEMailChangeEvent.EMailChange.actor, the given e-mail address as theEMailChangeEvent.EMailChange.newEmailand the newly created EMailVerificationToken as the [EMailChangeEvent.EMailChange.verificationToken].- Parameters:
newEMailAddress- The user wants to change their e-mail address to this value. Must be valid and allowed.- Throws:
NotLoggedInException- If the user is not authenticated.NotALocalUserException- If the Actor is not aLocalActor.NoDifferenceException- If the given new address matches the current one.AlreadyExistsException- If there already is an EMailVerificationToken for the Actor in the database. Can be any token for any new e-mail address value.InvalidOrBannedEMailAddressException- If the given new address is invalid or disallowed.
-
confirmNewEMail
@PreAuthorize("isFullyAuthenticated()") @NonNull public @NonNull Actor confirmNewEMail(@NonNull @NonNull String verificationToken) throws NotFoundException, ExpiredException, AccountIsLockedException, IllegalStateException, NotLoggedInException Changes theActor.eMailAddressof theVerificationToken.actorto the newEMailVerificationToken.eMailAddress.- Parameters:
verificationToken- TheVerificationToken.token. The EMailVerificationToken must belong to the current user.- Returns:
- The
VerificationToken.actor. - Throws:
NotLoggedInException- If the current user not authenticated.NotFoundException- If there is no EMailVerificationToken in the database where the token matches the given one and where theVerificationToken.actormatches the currently logged-in Actor.ExpiredException- If the token is no longer valid.AccountIsLockedException-If the
.invalid reference
Actor#isLocked()IllegalStateException- If the new e-mail address is not stored in the database.
-
onRegistration
Saves the registration date of the givenActorCreatedEventto theActorMetadatabelonging to theActorCreatedEvent.actor.- Parameters:
createdEvent- The registration event indicating the user that was newly created.
-
onLogin
@EventListener public void onLogin(@NonNull @NonNull org.springframework.security.authentication.event.AuthenticationSuccessEvent success) throws de.gustavblass.commons.exceptions.IllegalArgumentException - Parameters:
success- The login success event.- Throws:
de.gustavblass.commons.exceptions.IllegalArgumentException- If theAuthentication.getPrincipal()of the given success event is not anActor.- Implementation Note:
- Uses the
actorMetadataRepositoryand notActorRepository.save(Actor), because the authentication principal stored in the success event lacks theActor.password()and possibly other attributes as well. Saving the Actor would therefore delete possibly relevant data. It is far easier and less risky to just store the metadata itself.
-