public static <ID> boolean hasPermission(ID id, UserDto currentUser, String permission) { log.debug("Computing " + permission + " permission for User " + id + "\n Logged in user: " + currentUser); if (permission.equals("edit")) { if (currentUser == null) return false; boolean isSelf = currentUser.getId().equals(id.toString()); return isSelf || currentUser.isGoodAdmin(); // self or admin; } return false; } }
@Override public String getUsername() { return userDto.getUsername(); }
/** * Makes a User DTO */ public UserDto toUserDto() { UserDto userDto = new UserDto(); userDto.setId(getId().toString()); userDto.setUsername(email); userDto.setPassword(password); userDto.setRoles(roles); userDto.setTag(toTag()); userDto.initialize(); return userDto; }
@Override public Collection<? extends GrantedAuthority> getAuthorities() { Set<String> roles = userDto.getRoles(); Collection<LemonGrantedAuthority> authorities = roles.stream() .map(role -> new LemonGrantedAuthority("ROLE_" + role)) .collect(Collectors.toCollection(() -> new ArrayList<LemonGrantedAuthority>(roles.size() + 2))); if (userDto.isGoodUser()) { authorities.add(new LemonGrantedAuthority("ROLE_" + LecUtils.GOOD_USER)); if (userDto.isGoodAdmin()) authorities.add(new LemonGrantedAuthority("ROLE_" + LecUtils.GOOD_ADMIN)); } return authorities; }
@Override protected void updateUserFields(User user, User updatedUser, UserDto currentUser) { super.updateUserFields(user, updatedUser, currentUser); user.setName(updatedUser.getName()); LecjUtils.afterCommit(() -> { if (currentUser.getId().equals(user.getId().toString())) currentUser.setTag(user.toTag()); }); }
@Override public Optional<ID> getCurrentAuditor() { UserDto user = currentUser(); if (user == null) return Optional.empty(); return Optional.of(idConverter.toId(user.getId())); } }
/** * Fetches a new token - for session scrolling etc. * @return */ @PreAuthorize("isAuthenticated()") public String fetchNewToken(Optional<Long> expirationMillis, Optional<String> optionalUsername) { UserDto currentUser = LecwUtils.currentUser(); String username = optionalUsername.orElse(currentUser.getUsername()); LecUtils.ensureAuthority(currentUser.getUsername().equals(username) || currentUser.isGoodAdmin(), "com.naturalprogrammer.spring.notGoodAdminOrSameUser"); return LecUtils.TOKEN_PREFIX + blueTokenService.createToken(BlueTokenService.AUTH_AUDIENCE, username, expirationMillis.orElse(properties.getJwt().getExpirationMillis())); }
/** * Changes the password. */ @UserEditPermission @Transactional(propagation=Propagation.REQUIRED, readOnly=false) public String changePassword(U user, @Valid ChangePasswordForm changePasswordForm) { log.debug("Changing password for user: " + user); // Get the old password of the logged in user (logged in user may be an ADMIN) UserDto currentUser = LecwUtils.currentUser(); U loggedIn = userRepository.findById(toId(currentUser.getId())).get(); String oldPassword = loggedIn.getPassword(); // checks LexUtils.ensureFound(user); LexUtils.validateField("changePasswordForm.oldPassword", passwordEncoder.matches(changePasswordForm.getOldPassword(), oldPassword), "com.naturalprogrammer.spring.wrong.password").go(); // sets the password user.setPassword(passwordEncoder.encode(changePasswordForm.getPassword())); user.setCredentialsUpdatedMillis(System.currentTimeMillis()); userRepository.save(user); log.debug("Changed password for user: " + user); return user.toUserDto().getUsername(); }
@Override public void eraseCredentials() { userDto.setPassword(null); attributes = null; claims = null; userInfo = null; idToken = null; } }
public Mono<UserDto> changePassword(ID userId, Mono<ChangePasswordForm> changePasswordForm) { return Mono.zip(findUserById(userId), LecrUtils.currentUser()) .doOnNext(this::ensureEditable) .flatMap(tuple -> Mono.zip( Mono.just(tuple.getT1()), findUserById(toId(tuple.getT2().get().getId())), changePasswordForm) .doOnNext(this::changePassword)) .map(Tuple2::getT1) .flatMap(userRepository::save) .map(AbstractMongoUser::toUserDto); }
@PreAuthorize("isAuthenticated()") public Mono<Map<String, String>> fetchNewToken(ServerWebExchange exchange) { return Mono.zip(LecrUtils.currentUser(), exchange.getFormData()).map(tuple -> { UserDto currentUser = (UserDto) tuple.getT1().get(); String username = tuple.getT2().getFirst("username"); if (StringUtils.isBlank(username)) username = currentUser.getUsername(); long expirationMillis = getExpirationMillis(tuple.getT2()); LecUtils.ensureAuthority(currentUser.getUsername().equals(username) || currentUser.isGoodAdmin(), "com.naturalprogrammer.spring.notGoodAdminOrSameUser"); return Collections.singletonMap("token", LecUtils.TOKEN_PREFIX + blueTokenService.createToken(blueTokenService.AUTH_AUDIENCE, username, expirationMillis)); }); }
@Override protected UserDto fetchUserDto(JWTClaimsSet claims) { String username = claims.getSubject(); U user = userDetailsService.findUserByUsername(username) .orElseThrow(() -> new UsernameNotFoundException(username)); log.debug("User found ..."); LemonUtils.ensureCredentialsUpToDate(claims, user); UserDto userDto = user.toUserDto(); userDto.setPassword(null); return userDto; } }
/** * Makes a User DTO */ public UserDto toUserDto() { UserDto userDto = new UserDto(); userDto.setId(getId().toString()); userDto.setUsername(email); userDto.setPassword(password); // roles would be org.hibernate.collection.internal.PersistentSet, // which is not in another microservices not having Hibernate. // So, let's convert it to HashSet userDto.setRoles(new HashSet<String>(roles)); userDto.setTag(toTag()); userDto.initialize(); return userDto; }
/** * Updates the fields of the users. Override this if you have more fields. */ protected void updateUserFields(U user, U updatedUser, UserDto currentUser) { log.debug("Updating user fields for user: " + user); // Another good admin must be logged in to edit roles if (currentUser.isGoodAdmin() && !currentUser.getId().equals(user.getId().toString())) { log.debug("Updating roles for user: " + user); // update the roles if (user.getRoles().equals(updatedUser.getRoles())) // roles are same return; if (updatedUser.hasRole(UserUtils.Role.UNVERIFIED)) { if (!user.hasRole(UserUtils.Role.UNVERIFIED)) { makeUnverified(user); // make user unverified } } else { if (user.hasRole(UserUtils.Role.UNVERIFIED)) user.getRoles().remove(UserUtils.Role.UNVERIFIED); // make user verified } user.setRoles(updatedUser.getRoles()); user.setCredentialsUpdatedMillis(System.currentTimeMillis()); } }
protected void addAuthHeader(ServerHttpResponse response, UserDto userDto, long expirationMillis) { log.debug("Adding auth header for " + userDto.getUsername()); response.getHeaders().add(LecUtils.TOKEN_RESPONSE_HEADER_NAME, LecUtils.TOKEN_PREFIX + blueTokenService.createToken(BlueTokenService.AUTH_AUDIENCE, userDto.getUsername(), expirationMillis)); }
@PreAuthorize("isAuthenticated()") public Mono<UserDto> changeEmail(ID userId, Mono<MultiValueMap<String, String>> formData) { log.debug("Changing email of current user ..."); return LecrUtils.currentUser() .doOnNext(currentUser -> { LexUtils.validate(userId.equals(toId(currentUser.get().getId())), "com.naturalprogrammer.spring.wrong.login").go(); }) .then(Mono.zip(findUserById(userId), formData)) .map(this::validateChangeEmail) .flatMap(user -> Mono.zip(Mono.just(user), userRepository .findByEmail(user.getNewEmail()) .map(Optional::of) .defaultIfEmpty(Optional.empty()) )) .map(this::changeEmail) .flatMap(userRepository::save) .map(AbstractMongoUser::toUserDto); }
/** * Updates a user with the given data. */ @UserEditPermission @Validated(UserUtils.UpdateValidation.class) @Transactional(propagation=Propagation.REQUIRED, readOnly=false) public UserDto updateUser(U user, @Valid U updatedUser) { log.debug("Updating user: " + user); // checks LecjUtils.ensureCorrectVersion(user, updatedUser); // delegates to updateUserFields updateUserFields(user, updatedUser, LecwUtils.currentUser()); userRepository.save(user); log.debug("Updated user: " + user); UserDto userDto = user.toUserDto(); userDto.setPassword(null); return userDto; }
/** * Updates the fields of the users. Override this if you have more fields. */ protected void updateUserFields(U user, U updatedUser, UserDto currentUser) { log.debug("Updating user fields for user: " + user); // Another good admin must be logged in to edit roles if (currentUser.isGoodAdmin() && !currentUser.getId().equals(user.getId().toString())) { log.debug("Updating roles for user: " + user); // update the roles if (user.getRoles().equals(updatedUser.getRoles())) // roles are same return; if (updatedUser.hasRole(UserUtils.Role.UNVERIFIED)) { if (!user.hasRole(UserUtils.Role.UNVERIFIED)) { makeUnverified(user); // make user unverified } } else { if (user.hasRole(UserUtils.Role.UNVERIFIED)) user.getRoles().remove(UserUtils.Role.UNVERIFIED); // make user verified } user.setRoles(updatedUser.getRoles()); user.setCredentialsUpdatedMillis(System.currentTimeMillis()); } }
/** * returns the current user and a new authorization token in the response */ public Mono<UserDto> userWithToken(Mono<UserDto> userDto, ServerHttpResponse response, long expirationMillis) { return userDto.doOnNext(user -> { log.debug("Adding auth header for " + user.getUsername()); addAuthHeader(response, user, expirationMillis); }); }
public Mono<Void> requestEmailChange(ID userId, Mono<EmailForm> emailForm) { return Mono.zip(findUserById(userId), LecrUtils.currentUser()) .doOnNext(this::ensureEditable) .flatMap(tuple -> Mono.zip( Mono.just(tuple.getT1()), findUserById(toId(tuple.getT2().get().getId())), emailForm) .doOnNext(this::requestEmailChange)) .map(Tuple2::getT1) .flatMap(userRepository::save) .doOnNext(this::mailChangeEmailLink) .then(); }