keyValues;
44 |
45 | public static UpdateProfileRequest init(AppUserReference user) {
46 | return UpdateProfileRequest.builder()
47 | .firstName(user.getFirstName())
48 | .lastName(user.getLastName())
49 | .avatar(user.getAvatar())
50 | .keyValues(new HashMap<>())
51 | .build();
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/authentication/UsernameChangeRequest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.authentication;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | import javax.validation.constraints.NotNull;
10 | import java.io.Serializable;
11 |
12 | /**
13 | * body to change username
14 | */
15 | @Data
16 | @Builder
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | @Schema(description = "body to change username")
20 | public class UsernameChangeRequest implements Serializable {
21 |
22 | @NotNull
23 | private String newUsername;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/forgot/ForgotPasswordRequest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.forgot;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | import javax.annotation.Nullable;
10 | import javax.validation.constraints.Email;
11 | import java.io.Serializable;
12 |
13 | /**
14 | * body of password forgot process
15 | */
16 | @Data
17 | @Builder
18 | @NoArgsConstructor
19 | @AllArgsConstructor
20 | @Schema(description = "body of password forgot process")
21 | public class ForgotPasswordRequest implements Serializable {
22 |
23 | @Nullable
24 | private String username;
25 |
26 | @Email
27 | @Nullable
28 | private String email;
29 |
30 | /**
31 | * optional parameter to overwrite system default
32 | *
33 | * full qualified url to a custom UI that proceed the password reset
34 | * * ?verification=VALUE will get append
35 | */
36 | @Nullable
37 | @Schema(description = "optional parameter to overwrite system default\n" +
38 | "full qualified url to a custom UI that proceed the password reset.\n" +
39 | "* ?verification=VALUE will get append")
40 | private String resetPasswordUrl;
41 |
42 |
43 | /**
44 | * please use resetPasswordUrl will get removed in future
45 | */
46 | @Deprecated
47 | @Nullable
48 | @Schema(description = "please use resetPasswordUrl will get removed in future", deprecated = true)
49 | private String verificationUrl;
50 | }
51 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/forgot/PerformPasswordResetRequest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.forgot;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import lombok.*;
5 |
6 | import javax.validation.constraints.NotNull;
7 | import java.io.Serializable;
8 |
9 | /**
10 | * body for password change after forgot triggered
11 | */
12 | @Data
13 | @Builder
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | @ToString(exclude = {"password"})
17 | @Schema(description = "body for password change after forgot triggered")
18 | public class PerformPasswordResetRequest implements Serializable {
19 |
20 | @NotNull
21 | private String verification;
22 |
23 | @NotNull
24 | private String password;
25 | }
26 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/registration/RegistrationRequest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.registration;
2 |
3 | import io.rocketbase.commons.model.HasFirstAndLastName;
4 | import io.rocketbase.commons.model.HasKeyValue;
5 | import io.swagger.v3.oas.annotations.media.Schema;
6 | import lombok.*;
7 |
8 | import javax.annotation.Nullable;
9 | import javax.validation.constraints.Email;
10 | import javax.validation.constraints.NotNull;
11 | import java.io.Serializable;
12 | import java.util.Map;
13 |
14 | /**
15 | * body for registration as new user
16 | */
17 | @Data
18 | @Builder
19 | @NoArgsConstructor
20 | @AllArgsConstructor
21 | @ToString(exclude = {"password"})
22 | @Schema(description = "body for registration as new user")
23 | public class RegistrationRequest implements Serializable, HasKeyValue, HasFirstAndLastName {
24 |
25 | @NotNull
26 | private String username;
27 |
28 | @Nullable
29 | private String firstName;
30 |
31 | @Nullable
32 | private String lastName;
33 |
34 | @NotNull
35 | @Email
36 | private String email;
37 |
38 | @NotNull
39 | private String password;
40 |
41 | @Nullable
42 | private Map keyValues;
43 |
44 | /**
45 | * optional parameter to overwrite system default
46 | *
47 | * full qualified url to a custom UI that proceed the verification
48 | * * ?verification=VALUE will get append
49 | */
50 | @Nullable
51 | @Schema(description = "optional parameter to overwrite system default.\n" +
52 | "full qualified url to a custom UI that proceed the verification.\n" +
53 | "* ?verification=VALUE will get append")
54 | private String verificationUrl;
55 | }
56 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/EmailErrorCodes.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.validation;
2 |
3 | import com.fasterxml.jackson.annotation.JsonValue;
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 |
6 | @Schema(enumAsRef = true)
7 | public enum EmailErrorCodes {
8 | ALREADY_TAKEN("alreadyTaken"),
9 | INVALID("invalid"),
10 | TOO_LONG("tooLong");
11 |
12 | private final String value;
13 |
14 | EmailErrorCodes(String value) {
15 | this.value = value;
16 | }
17 |
18 | @JsonValue
19 | public String getValue() {
20 | return value;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/PasswordErrorCodes.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.validation;
2 |
3 | import com.fasterxml.jackson.annotation.JsonValue;
4 |
5 | public enum PasswordErrorCodes {
6 | TOO_SHORT("tooShort"),
7 | TOO_LONG("tooLong"),
8 | INSUFFICIENT_LOWERCASE("insufficientLowercase"),
9 | INSUFFICIENT_UPPERCASE("insufficientUppercase"),
10 | INSUFFICIENT_DIGIT("insufficientDigit"),
11 | INSUFFICIENT_SPECIAL("insufficientSpecial"),
12 | INVALID_CURRENT_PASSWORD("invalidCurrentPassword");
13 |
14 | private final String value;
15 |
16 | PasswordErrorCodes(String value) {
17 | this.value = value;
18 | }
19 |
20 | @JsonValue
21 | public String getValue() {
22 | return value;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/TokenErrorCodes.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.validation;
2 |
3 | import com.fasterxml.jackson.annotation.JsonValue;
4 |
5 | public enum TokenErrorCodes {
6 | EXPIRED("expired"),
7 | INVALID("invalid");
8 |
9 | private final String value;
10 |
11 | TokenErrorCodes(String value) {
12 | this.value = value;
13 | }
14 |
15 | @JsonValue
16 | public String getValue() {
17 | return value;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/UsernameErrorCodes.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.validation;
2 |
3 | import com.fasterxml.jackson.annotation.JsonValue;
4 |
5 | public enum UsernameErrorCodes {
6 | ALREADY_TAKEN("alreadyTaken"),
7 | TOO_SHORT("tooShort"),
8 | TOO_LONG("tooLong"),
9 | NOT_ALLOWED_CHAR("notAllowedChar");
10 |
11 | private final String value;
12 |
13 | UsernameErrorCodes(String value) {
14 | this.value = value;
15 | }
16 |
17 | @JsonValue
18 | public String getValue() {
19 | return value;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/dto/validation/ValidationResponse.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.dto.validation;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.annotation.JsonSubTypes;
5 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
6 | import com.google.common.base.Joiner;
7 | import lombok.*;
8 |
9 | import java.io.Serializable;
10 | import java.util.Map;
11 |
12 | @Data
13 | @Builder
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@type")
17 | @JsonSubTypes({
18 | @JsonSubTypes.Type(value = UsernameErrorCodes.class, name = "username"),
19 | @JsonSubTypes.Type(value = PasswordErrorCodes.class, name = "password"),
20 | @JsonSubTypes.Type(value = EmailErrorCodes.class, name = "email"),
21 | @JsonSubTypes.Type(value = TokenErrorCodes.class, name = "token")})
22 | public class ValidationResponse implements Serializable {
23 |
24 | private boolean valid;
25 |
26 | @Singular
27 | private Map errorCodes;
28 |
29 | @JsonIgnore
30 | public String getMessage(String separator) {
31 | if (!errorCodes.isEmpty()) {
32 | return Joiner.on(separator).join(errorCodes.values());
33 | }
34 | return null;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/AuthErrorCodes.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import com.fasterxml.jackson.annotation.JsonValue;
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Getter;
6 | import lombok.RequiredArgsConstructor;
7 |
8 | @RequiredArgsConstructor
9 | @Schema(enumAsRef = true)
10 | public enum AuthErrorCodes {
11 | REGISTRATION(1010, "registration"),
12 | VERIFICATION_INVALID(1011, "verificationInvalid"),
13 | UNKNOWN_USER(1012, "unknownUser"),
14 | VALIDATION(1013, "validation");
15 |
16 | @Getter
17 | private final int status;
18 | private final String value;
19 |
20 | @JsonValue
21 | public String getValue() {
22 | return value;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/BaseValidationException.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import com.google.common.base.Joiner;
4 |
5 | import java.util.Set;
6 | import java.util.stream.Collectors;
7 |
8 | public interface BaseValidationException> {
9 | Set> getErrors();
10 |
11 | /**
12 | * joins all error message to one string
13 | * returns empty string when no errors exist
14 | */
15 | default String getErrorsMessage() {
16 | if (getErrors() != null) {
17 | return Joiner.on("; ").skipNulls().join(getErrors().stream().map(e -> e.getMessage()).collect(Collectors.toList()));
18 | }
19 | return "";
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/EmailValidationException.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import io.rocketbase.commons.dto.validation.EmailErrorCodes;
4 | import lombok.Getter;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.ToString;
7 |
8 | import java.util.Set;
9 |
10 | @Getter
11 | @ToString
12 | @RequiredArgsConstructor
13 | public class EmailValidationException extends RuntimeException implements BaseValidationException {
14 |
15 | private final Set> errors;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/PasswordValidationException.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import io.rocketbase.commons.dto.validation.PasswordErrorCodes;
4 | import lombok.Getter;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.ToString;
7 |
8 | import java.util.Set;
9 |
10 | @Getter
11 | @ToString
12 | @RequiredArgsConstructor
13 | public class PasswordValidationException extends RuntimeException implements BaseValidationException {
14 |
15 | private final Set> errors;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/RegistrationException.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import io.rocketbase.commons.dto.validation.EmailErrorCodes;
4 | import io.rocketbase.commons.dto.validation.PasswordErrorCodes;
5 | import io.rocketbase.commons.dto.validation.UsernameErrorCodes;
6 | import lombok.Getter;
7 | import lombok.RequiredArgsConstructor;
8 | import lombok.ToString;
9 |
10 | import java.util.LinkedHashSet;
11 | import java.util.Set;
12 |
13 | @Getter
14 | @ToString
15 | @RequiredArgsConstructor
16 | public class RegistrationException extends RuntimeException implements BaseValidationException {
17 |
18 | private final Set> usernameErrors;
19 | private final Set> passwordErrors;
20 | private final Set> emailErrors;
21 |
22 | @Override
23 | public Set getErrors() {
24 | Set result = new LinkedHashSet<>();
25 | if (hasUsernameErrors()) {
26 | result.addAll(usernameErrors);
27 | }
28 | if (hasPasswordErrors()) {
29 | result.addAll(passwordErrors);
30 | }
31 | if (hasEmailErrors()) {
32 | result.addAll(emailErrors);
33 | }
34 | return null;
35 | }
36 |
37 | public boolean hasUsernameErrors() {
38 | return usernameErrors != null && !usernameErrors.isEmpty();
39 | }
40 |
41 | public boolean hasPasswordErrors() {
42 | return passwordErrors != null && !passwordErrors.isEmpty();
43 | }
44 |
45 | public boolean hasEmailErrors() {
46 | return emailErrors != null && !emailErrors.isEmpty();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/TokenRefreshException.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | public class TokenRefreshException extends RuntimeException {
4 | }
5 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/UnknownUserException.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import lombok.Getter;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.ToString;
6 |
7 | @ToString
8 | @RequiredArgsConstructor
9 | @Getter
10 | public class UnknownUserException extends RuntimeException {
11 |
12 | private final boolean email;
13 | private final boolean username;
14 | }
15 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/UsernameValidationException.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import io.rocketbase.commons.dto.validation.UsernameErrorCodes;
4 | import lombok.Getter;
5 | import lombok.RequiredArgsConstructor;
6 | import lombok.ToString;
7 |
8 | import java.util.Set;
9 |
10 | @Getter
11 | @ToString
12 | @RequiredArgsConstructor
13 | public class UsernameValidationException extends RuntimeException {
14 |
15 | private final Set> errors;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/ValidationErrorCode.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import lombok.EqualsAndHashCode;
4 | import lombok.Getter;
5 | import lombok.RequiredArgsConstructor;
6 |
7 | @Getter
8 | @EqualsAndHashCode(of = "code")
9 | @RequiredArgsConstructor
10 | public class ValidationErrorCode> {
11 |
12 | private final T code;
13 | private final String field;
14 | private final String message;
15 |
16 | public ValidationErrorCode(T code) {
17 | this.code = code;
18 | message = null;
19 | field = null;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/exception/VerificationException.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.exception;
2 |
3 | import lombok.Getter;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.ToString;
6 |
7 | @ToString
8 | @Getter
9 | @RequiredArgsConstructor
10 | public class VerificationException extends RuntimeException {
11 |
12 | private final String field;
13 | }
14 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/model/AppUserReference.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
5 | import io.swagger.v3.oas.annotations.media.Schema;
6 |
7 | import javax.annotation.Nullable;
8 | import java.io.Serializable;
9 |
10 | /**
11 | * short representation of an appuser
12 | */
13 | @JsonDeserialize(as = SimpleAppUserReference.class)
14 | @Schema(description = "short representation of an appuser")
15 | public interface AppUserReference extends HasFirstAndLastName, Serializable {
16 |
17 | String getId();
18 |
19 | String getUsername();
20 |
21 | String getEmail();
22 |
23 | @Nullable
24 | String getAvatar();
25 |
26 | /**
27 | * fullname fallback if null use username
28 | */
29 | @JsonIgnore
30 | default String getDisplayName() {
31 | String fullName = getFullName();
32 | if (fullName == null) {
33 | return getUsername();
34 | }
35 | return fullName;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/model/AppUserToken.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model;
2 |
3 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * AppUserReference + role information + keyValues
10 | */
11 | @JsonDeserialize(as = SimpleAppUserToken.class)
12 | @Schema(description = "AppUserReference + role information + keyValues")
13 | public interface AppUserToken extends AppUserReference, HasKeyValue {
14 |
15 | List getRoles();
16 |
17 | /**
18 | * checks if user has role with name (ignore cases)
19 | *
20 | * @param role name of role to search
21 | * @return true when exists
22 | */
23 | default boolean hasRole(String role) {
24 | if (getRoles() != null && role != null) {
25 | for (String r : getRoles()) {
26 | if (role.equalsIgnoreCase(r)) {
27 | return true;
28 | }
29 | }
30 | }
31 | return false;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/model/SimpleAppUserReference.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model;
2 |
3 | import lombok.*;
4 |
5 | /**
6 | * simplified AppUser without keyValues, password, audit etc...
7 | * used to store a simple representation as a copy of AppUser in mongo or elsewhere
8 | */
9 | @Getter
10 | @Builder
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | @EqualsAndHashCode(of = "id")
14 | public class SimpleAppUserReference implements AppUserReference {
15 |
16 | private String id;
17 |
18 | private String username;
19 |
20 | private String firstName;
21 |
22 | private String lastName;
23 |
24 | private String email;
25 |
26 | private String avatar;
27 | }
28 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/model/SimpleAppUserToken.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model;
2 |
3 | import com.google.common.collect.ImmutableMap;
4 | import lombok.*;
5 |
6 | import java.util.HashMap;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | @Data
11 | @AllArgsConstructor
12 | @NoArgsConstructor
13 | @Builder
14 | public class SimpleAppUserToken implements AppUserToken {
15 |
16 | private String id;
17 |
18 | private String username;
19 |
20 | private String firstName;
21 |
22 | private String lastName;
23 |
24 | private String email;
25 |
26 | private String avatar;
27 |
28 | private List roles;
29 |
30 | @Getter(AccessLevel.PROTECTED)
31 | @Setter(AccessLevel.PROTECTED)
32 | private Map keyValueMap = new HashMap<>();
33 |
34 | public SimpleAppUserToken(String id, String username, List roles) {
35 | this.id = id;
36 | this.username = username;
37 | this.roles = roles;
38 | }
39 |
40 | @Override
41 | public Map getKeyValues() {
42 | return getKeyValueMap() != null ? ImmutableMap.copyOf(getKeyValueMap()) : null;
43 | }
44 |
45 | @Override
46 | public void setKeyValues(Map map) {
47 | keyValueMap = map;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/resource/ImpersonateResource.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.resource;
2 |
3 | import io.rocketbase.commons.adapters.JwtRestTemplate;
4 | import io.rocketbase.commons.api.ImpersonateApi;
5 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
6 | import lombok.SneakyThrows;
7 | import org.springframework.http.HttpEntity;
8 | import org.springframework.http.HttpMethod;
9 | import org.springframework.util.Assert;
10 | import org.springframework.web.client.RestTemplate;
11 |
12 | /**
13 | * api resource used by admins to impersonate as someone else
14 | */
15 | public class ImpersonateResource implements BaseRestResource, ImpersonateApi {
16 |
17 | public static final String API_IMPERSONATE = "/api/impersonate/";
18 | protected RestTemplate restTemplate;
19 | protected String baseAuthApiUrl;
20 |
21 | public ImpersonateResource(String baseAuthApiUrl, RestTemplate restTemplate) {
22 | Assert.hasText(baseAuthApiUrl, "baseAuthApiUrl is required");
23 | this.restTemplate = restTemplate;
24 | this.baseAuthApiUrl = baseAuthApiUrl;
25 | }
26 |
27 | public ImpersonateResource(JwtRestTemplate restTemplate) {
28 | this.restTemplate = restTemplate;
29 | this.baseAuthApiUrl = restTemplate.getTokenProvider().getBaseAuthApiUrl();
30 | }
31 |
32 | @Override
33 | @SneakyThrows
34 | public JwtTokenBundle impersonate(String userIdOrUsername) {
35 | return restTemplate.exchange(createUriComponentsBuilder(baseAuthApiUrl)
36 | .path(API_IMPERSONATE)
37 | .path(userIdOrUsername).toUriString(),
38 | HttpMethod.GET,
39 | new HttpEntity<>(createHeaderWithLanguage()),
40 | JwtTokenBundle.class).getBody();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/util/JwtTokenBody.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.util;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | import java.time.Instant;
9 | import java.util.List;
10 |
11 | @Setter
12 | @JsonIgnoreProperties(ignoreUnknown = true)
13 | public class JwtTokenBody {
14 |
15 | /**
16 | * token creation date
17 | */
18 | private Long iat;
19 | /**
20 | * expiration
21 | */
22 | private Long exp;
23 | /**
24 | * username
25 | */
26 | private String sub;
27 |
28 | @Getter
29 | @JsonProperty("user_id")
30 | private String userId;
31 |
32 | @Getter
33 | /**
34 | * roles
35 | */
36 | private List scopes;
37 |
38 | public boolean isExpired() {
39 | if (exp != null) {
40 | return getExpiration().isBefore(Instant.now());
41 | }
42 | return false;
43 | }
44 |
45 | public Instant getExpiration() {
46 | if (exp != null) {
47 | return Instant.ofEpochSecond(exp, 0);
48 | }
49 | return null;
50 | }
51 |
52 | public Instant getIssuedAt() {
53 | if (iat != null) {
54 | return Instant.ofEpochSecond(iat, 0);
55 | }
56 | return null;
57 | }
58 |
59 | public String getUsername() {
60 | return sub;
61 | }
62 |
63 | public boolean hasRole(String name) {
64 | return scopes != null && scopes.stream()
65 | .filter(s -> s.equalsIgnoreCase(name))
66 | .findFirst().isPresent();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/util/JwtTokenDecoder.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.util;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 |
5 | import java.util.Base64;
6 |
7 | public final class JwtTokenDecoder {
8 |
9 | public static JwtTokenBody decodeTokenBody(String token) {
10 | if (token != null) {
11 | String[] split = token.split("\\.");
12 | if (split.length == 3) {
13 | try {
14 | byte[] body = Base64.getUrlDecoder().decode(split[1]);
15 | return new ObjectMapper().readValue(body, JwtTokenBody.class);
16 | } catch (Exception e) {
17 | }
18 | }
19 | }
20 | return null;
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/util/JwtTokenStore.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.util;
2 |
3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
4 | import io.rocketbase.commons.exception.TokenRefreshException;
5 |
6 | import java.io.Serializable;
7 |
8 | public interface JwtTokenStore extends Serializable {
9 |
10 | boolean checkTokenNeedsRefresh();
11 |
12 | boolean checkTokenNeedsRefresh(long seconds);
13 |
14 | void refreshToken() throws TokenRefreshException;
15 |
16 | String getHeaderName();
17 |
18 | String getTokenHeader();
19 |
20 | JwtTokenBundle getTokenBundle();
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/commons-auth-api/src/main/java/io/rocketbase/commons/util/UsernameGenerator.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.util;
2 |
3 | import org.springframework.util.StringUtils;
4 |
5 | import java.text.Normalizer;
6 |
7 | public abstract class UsernameGenerator {
8 |
9 | private static String[][] UMLAUT_REPLACEMENTS = {{"Ä", "Ae"}, {"Ü", "Ue"}, {"Ö", "Oe"}, {"ä", "ae"}, {"ü", "ue"}, {"ö", "oe"}, {"ß", "ss"}};
10 |
11 | public static String replaceUmlaute(String orig) {
12 | String result = Nulls.notNull(orig) + "";
13 | for (int i = 0; i < UMLAUT_REPLACEMENTS.length; i++) {
14 | result = result.replace(UMLAUT_REPLACEMENTS[i][0], UMLAUT_REPLACEMENTS[i][1]);
15 | }
16 | return result;
17 | }
18 |
19 | public static String normalizeString(String input) {
20 | String result = Nulls.notNull(input) + "";
21 | result = replaceUmlaute(result);
22 | result = Normalizer.normalize(result, Normalizer.Form.NFD)
23 | .replaceAll("[^\\p{ASCII}]", "");
24 | return result.toLowerCase().replaceAll("[^a-z0-9\\.\\-\\_]*", "");
25 | }
26 |
27 | public static String byFirstAndLastName(String firstName, String lastName) {
28 | String result = "";
29 | if (!StringUtils.isEmpty(firstName)) {
30 | result += firstName;
31 | }
32 | if (!StringUtils.isEmpty(lastName)) {
33 | if (result.length() > 0) {
34 | result += ".";
35 | }
36 | result += lastName;
37 | }
38 | return normalizeString(result);
39 | }
40 |
41 | public static String byEmail(String email) {
42 | int atIndex = Nulls.notNull(email).lastIndexOf("@");
43 | if (atIndex <= 0) {
44 | return null;
45 | }
46 | return normalizeString(email.substring(0, atIndex));
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/commons-auth-api/src/test/java/io/rocketbase/commons/util/UsernameGeneratorTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.util;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.hamcrest.MatcherAssert.assertThat;
6 | import static org.hamcrest.Matchers.is;
7 |
8 | public class UsernameGeneratorTest {
9 |
10 | @Test
11 | public void replaceUmlaute() {
12 | // given
13 | String input = "ÖlapalümäAß";
14 | // when
15 | String result = UsernameGenerator.replaceUmlaute(input);
16 | // then
17 | assertThat(result, is("OelapaluemaeAss"));
18 | }
19 |
20 | @Test
21 | public void normalizeString() {
22 | // given
23 | String input = "ÄöüMte@e° eé?ß# +´´";
24 | // when
25 | String result = UsernameGenerator.normalizeString(input);
26 | // then
27 | assertThat(result, is("aeoeuemteeeess"));
28 | }
29 |
30 | @Test
31 | public void byFirstAndLastName() {
32 | // given
33 | String firstName = "Ünal";
34 | String lastName = "MöllerPütt";
35 | // when
36 | String result = UsernameGenerator.byFirstAndLastName(firstName, lastName);
37 | // then
38 | assertThat(result, is("uenal.moellerpuett"));
39 | }
40 |
41 | @Test
42 | public void byEmail() {
43 | // given
44 | String email = "Süper-user@web.de";
45 | // when
46 | String result = UsernameGenerator.byEmail(email);
47 | // then
48 | assertThat(result, is("sueper-user"));
49 | }
50 | }
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/adapters/AuthClientRequestFactory.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.adapters;
2 |
3 |
4 | import io.rocketbase.commons.security.CommonsAuthenticationToken;
5 | import io.rocketbase.commons.util.JwtTokenStore;
6 | import org.apache.http.client.methods.HttpUriRequest;
7 | import org.springframework.http.client.ClientHttpRequestFactory;
8 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
9 | import org.springframework.security.core.Authentication;
10 | import org.springframework.security.core.context.SecurityContextHolder;
11 |
12 | public class AuthClientRequestFactory extends HttpComponentsClientHttpRequestFactory implements ClientHttpRequestFactory {
13 |
14 | @Override
15 | protected void postProcessHttpRequest(HttpUriRequest request) {
16 | JwtTokenStore jwtTokenStore = getCommonsAuthenticationToken().getJwtTokenStore();
17 | if (jwtTokenStore.checkTokenNeedsRefresh()) {
18 | jwtTokenStore.refreshToken();
19 | }
20 | request.setHeader(jwtTokenStore.getHeaderName(), jwtTokenStore.getTokenHeader());
21 | }
22 |
23 | protected CommonsAuthenticationToken getCommonsAuthenticationToken() {
24 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
25 | CommonsAuthenticationToken token;
26 |
27 | if (authentication == null) {
28 | throw new IllegalStateException("Cannot set authorization header because there is no authenticated principal");
29 | }
30 |
31 | if (!CommonsAuthenticationToken.class.isAssignableFrom(authentication.getClass())) {
32 | throw new IllegalStateException(
33 | String.format(
34 | "Cannot set authorization header because Authentication is of type %s but %s is required",
35 | authentication.getClass(), CommonsAuthenticationToken.class)
36 | );
37 | }
38 |
39 | token = (CommonsAuthenticationToken) authentication;
40 | return token;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/adapters/AuthRestTemplate.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.adapters;
2 |
3 | import io.rocketbase.commons.resource.BasicResponseErrorHandler;
4 | import org.springframework.web.client.RestOperations;
5 | import org.springframework.web.client.RestTemplate;
6 |
7 | public class AuthRestTemplate extends RestTemplate implements RestOperations {
8 |
9 | /**
10 | * use SecurityContext as source for authentications
11 | */
12 | public AuthRestTemplate(AuthClientRequestFactory requestFactory) {
13 | super(requestFactory);
14 | init();
15 | }
16 |
17 | /**
18 | * login user once and work with it's credentials
19 | */
20 | public AuthRestTemplate(AuthClientLoginRequestFactory requestFactory) {
21 | super(requestFactory);
22 | init();
23 | }
24 |
25 | /**
26 | * login user once and work with it's credentials
27 | */
28 | public AuthRestTemplate(String baseAuthApiUrl, String username, String password) {
29 | super(new AuthClientLoginRequestFactory(baseAuthApiUrl, username, password));
30 | init();
31 | }
32 |
33 | protected void init() {
34 | setErrorHandler(new BasicResponseErrorHandler());
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/config/EmailProperties.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | @Data
7 | @ConfigurationProperties(prefix = "auth.email")
8 | public class EmailProperties {
9 |
10 | private String subjectPrefix = "[Auth]";
11 | private String serviceName = "commons-auth";
12 |
13 | private EmailLogo logo;
14 | private String greetingFrom = "commons-auth";
15 |
16 | private String supportEmail = "support@localhost";
17 | private String fromEmail = "no-reply@localhost";
18 | private String copyrightName = "commons-auth";
19 | private String copyrightUrl = "https://github.com/rocketbase-io/commons-auth";
20 |
21 | @Data
22 | public static class EmailLogo {
23 | private String src;
24 | private Integer width;
25 | private Integer height;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/config/FormsProperties.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import io.rocketbase.commons.util.UrlParts;
4 | import lombok.Data;
5 | import org.springframework.boot.context.properties.ConfigurationProperties;
6 |
7 | @Data
8 | @ConfigurationProperties(prefix = "auth.forms")
9 | public class FormsProperties {
10 |
11 | /**
12 | * prefix for the paths of the forms-controller
13 | */
14 | private String prefix = "";
15 |
16 | private String title = "commons-auth";
17 |
18 | private String logoSrc = "./assets/rocketbase.svg";
19 |
20 | /**
21 | * quick help to configure spring security
22 | */
23 | public String[] getFormEndpointPaths() {
24 | String prefixPath = UrlParts.ensureStartsAndEndsWithSlash(prefix);
25 | return new String[]{
26 | prefixPath + "login",
27 | prefixPath + "logout",
28 | prefixPath + "forgot",
29 | prefixPath + "reset-password",
30 | prefixPath + "verify-email"
31 | };
32 | }
33 |
34 | /**
35 | * quick help to configure spring security
36 | */
37 | public String[] getInviteEndpointPaths() {
38 | String prefixPath = UrlParts.ensureStartsAndEndsWithSlash(prefix);
39 | return new String[]{
40 | prefixPath + "invite"
41 | };
42 | }
43 |
44 | /**
45 | * quick help to configure spring security
46 | */
47 | public String[] getRegistrationEndpointPaths() {
48 | String prefixPath = UrlParts.ensureStartsAndEndsWithSlash(prefix);
49 | return new String[]{
50 | prefixPath + "registration",
51 | prefixPath + "verification"
52 | };
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/config/JwtProperties.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 | import org.springframework.http.HttpHeaders;
6 |
7 | import javax.validation.constraints.NotNull;
8 |
9 | @Data
10 | @ConfigurationProperties(prefix = "auth.jwt")
11 | public class JwtProperties {
12 |
13 |
14 | private String header = HttpHeaders.AUTHORIZATION;
15 | private String tokenPrefix = "Bearer ";
16 | private String uriParam = "token";
17 |
18 | @NotNull
19 | private String secret;
20 |
21 | /**
22 | * default 1 hour
23 | */
24 | private long accessTokenExpiration = 60;
25 |
26 | /**
27 | * default 30 days
28 | */
29 | private long refreshTokenExpiration = 43200;
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/config/PasswordProperties.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | @Data
7 | @ConfigurationProperties(prefix = "auth.password")
8 | public class PasswordProperties {
9 |
10 | private int minLength = 8;
11 |
12 | private int maxLength = 100;
13 |
14 | private int lowercase = 1;
15 |
16 | private int uppercase = 1;
17 |
18 | private int digit = 1;
19 |
20 | /**
21 | * character of this list:
22 | * !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
23 | */
24 | private int special = 1;
25 | }
26 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/config/RegistrationProperties.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 | import org.springframework.validation.annotation.Validated;
6 |
7 | @Data
8 | @ConfigurationProperties(prefix = "auth.registration")
9 | @Validated
10 | public class RegistrationProperties {
11 |
12 | private boolean enabled = true;
13 |
14 | /**
15 | * should use verify it's email-adress
16 | */
17 | private boolean verification = true;
18 |
19 | /**
20 | * in minutes - default 1 day
21 | */
22 | private long verificationExpiration = 1440;
23 |
24 | private String role = "USER";
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/config/UsernameProperties.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | @Data
7 | @ConfigurationProperties(prefix = "auth.username")
8 | public class UsernameProperties {
9 |
10 | private int minLength = 3;
11 |
12 | private int maxLength = 20;
13 |
14 | private String specialCharacters = ".-_";
15 | }
16 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/converter/AppUserConverter.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.converter;
2 |
3 | import io.rocketbase.commons.dto.appuser.AppUserRead;
4 | import io.rocketbase.commons.model.AppUserEntity;
5 | import io.rocketbase.commons.util.RolesAuthoritiesConverter;
6 |
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.Map;
10 | import java.util.stream.Collectors;
11 |
12 | public class AppUserConverter {
13 |
14 | public static Map filterInvisibleKeys(Map keyValues) {
15 | if (keyValues == null) {
16 | return null;
17 | }
18 | Map map = new HashMap<>();
19 | keyValues.entrySet().stream()
20 | .filter(e -> !e.getKey().startsWith("_"))
21 | .forEach(e -> map.put(e.getKey(), e.getValue()));
22 | return map;
23 | }
24 |
25 | public AppUserRead fromEntity(AppUserEntity entity) {
26 | if (entity == null) {
27 | return null;
28 | }
29 | return AppUserRead.builder()
30 | .id(entity.getId())
31 | .username(entity.getUsername())
32 | .firstName(entity.getFirstName())
33 | .lastName(entity.getLastName())
34 | .email(entity.getEmail())
35 | .avatar(entity.getAvatar())
36 | .roles(RolesAuthoritiesConverter.convertRoles(entity.getRoles()))
37 | .keyValues(filterInvisibleKeys(entity.getKeyValues()))
38 | .enabled(entity.isEnabled())
39 | .created(entity.getCreated())
40 | .lastLogin(entity.getLastLogin())
41 | .build();
42 | }
43 |
44 | public List fromEntities(List entities) {
45 | if (entities == null) {
46 | return null;
47 | }
48 | return entities.stream()
49 | .map(e -> fromEntity(e))
50 | .collect(Collectors.toList());
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/converter/ValidationConverter.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.converter;
2 |
3 | import io.rocketbase.commons.dto.validation.ValidationResponse;
4 | import io.rocketbase.commons.exception.ValidationErrorCode;
5 |
6 | import java.util.HashMap;
7 | import java.util.Set;
8 |
9 | public class ValidationConverter {
10 |
11 | public static > ValidationResponse convert(Set> errors) {
12 | ValidationResponse response = new ValidationResponse<>(errors != null && errors.isEmpty(), new HashMap<>());
13 | if (errors != null) {
14 | for (ValidationErrorCode c : errors) {
15 | response.getErrorCodes().put(c.getCode(), c.getMessage());
16 | }
17 | }
18 | return response;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/ActiveUserChangedEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import lombok.Getter;
4 | import org.springframework.context.ApplicationEvent;
5 |
6 | /**
7 | * will get trigged when amount of ActiveUserStore is changed
8 | */
9 | @Getter
10 | public class ActiveUserChangedEvent extends ApplicationEvent {
11 |
12 | public ActiveUserChangedEvent(Object source) {
13 | super(source);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/EmailChangeEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class EmailChangeEvent extends ApplicationEvent {
9 |
10 | private final String oldEmailAddress;
11 | private final AppUserEntity appUserEntity;
12 |
13 |
14 | public EmailChangeEvent(Object source, String oldEmailAddress, AppUserEntity appUserEntity) {
15 | super(source);
16 | this.oldEmailAddress = oldEmailAddress;
17 | this.appUserEntity = appUserEntity;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/ImpersonateEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserToken;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class ImpersonateEvent extends ApplicationEvent {
9 |
10 | private final AppUserToken requestedBy;
11 | private final AppUserToken impersonateAs;
12 |
13 | public ImpersonateEvent(Object source, AppUserToken requestedBy, AppUserToken impersonateAs) {
14 | super(source);
15 | this.requestedBy = requestedBy;
16 | this.impersonateAs = impersonateAs;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/InviteEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppInviteEntity;
4 | import io.rocketbase.commons.model.AppUserEntity;
5 | import lombok.Getter;
6 | import org.springframework.context.ApplicationEvent;
7 |
8 | import javax.annotation.Nullable;
9 |
10 | @Getter
11 | public class InviteEvent extends ApplicationEvent {
12 |
13 | private final AppInviteEntity appInviteEntity;
14 | private final InviteProcessType type;
15 |
16 | /**
17 | * only filled in case on processType confirm
18 | */
19 | @Nullable
20 | private AppUserEntity appUserEntity;
21 |
22 | public InviteEvent(Object source, AppInviteEntity appInviteEntity, InviteProcessType type) {
23 | super(source);
24 | this.appInviteEntity = appInviteEntity;
25 | this.type = type;
26 | }
27 |
28 | public InviteEvent(Object source, AppInviteEntity appInviteEntity, AppUserEntity appUserEntity) {
29 | super(source);
30 | this.appInviteEntity = appInviteEntity;
31 | this.type = InviteProcessType.CONFIRM;
32 | this.appUserEntity = appUserEntity;
33 | }
34 |
35 | public enum InviteProcessType {
36 | CREATE,
37 | VERIFY,
38 | CONFIRM
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/LoginEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class LoginEvent extends ApplicationEvent {
9 |
10 | private final AppUserEntity appUserEntity;
11 |
12 | public LoginEvent(Object source, AppUserEntity appUserEntity) {
13 | super(source);
14 | this.appUserEntity = appUserEntity;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/PasswordEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class PasswordEvent extends ApplicationEvent {
9 |
10 | private final AppUserEntity appUserEntity;
11 | private final PasswordProcessType type;
12 |
13 | public PasswordEvent(Object source, AppUserEntity appUserEntity, PasswordProcessType type) {
14 | super(source);
15 | this.appUserEntity = appUserEntity;
16 | this.type = type;
17 | }
18 |
19 | public enum PasswordProcessType {
20 | REQUEST_RESET,
21 | PROCEED_RESET,
22 | CHANGED
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/RefreshTokenEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class RefreshTokenEvent extends ApplicationEvent {
9 |
10 | private final AppUserEntity appUserEntity;
11 |
12 | public RefreshTokenEvent(Object source, AppUserEntity appUserEntity) {
13 | super(source);
14 | this.appUserEntity = appUserEntity;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/RegistrationEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class RegistrationEvent extends ApplicationEvent {
9 |
10 | private final AppUserEntity appUserEntity;
11 | private final RegistrationProcessType type;
12 |
13 | public RegistrationEvent(Object source, AppUserEntity appUserEntity, RegistrationProcessType type) {
14 | super(source);
15 | this.appUserEntity = appUserEntity;
16 | this.type = type;
17 | }
18 |
19 | public enum RegistrationProcessType {
20 | REGISTER,
21 | VERIFIED
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/RequestMeEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class RequestMeEvent extends ApplicationEvent {
9 |
10 | private final AppUserEntity appUserEntity;
11 |
12 | public RequestMeEvent(Object source, AppUserEntity appUserEntity) {
13 | super(source);
14 | this.appUserEntity = appUserEntity;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/UpdateProfileEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class UpdateProfileEvent extends ApplicationEvent {
9 |
10 | private final AppUserEntity appUserEntity;
11 |
12 | public UpdateProfileEvent(Object source, AppUserEntity appUserEntity) {
13 | super(source);
14 | this.appUserEntity = appUserEntity;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/event/UsernameChangeEvent.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.event;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import lombok.Getter;
5 | import org.springframework.context.ApplicationEvent;
6 |
7 | @Getter
8 | public class UsernameChangeEvent extends ApplicationEvent {
9 |
10 | private final String oldUsername;
11 | private final AppUserEntity appUserEntity;
12 |
13 |
14 | public UsernameChangeEvent(Object source, String oldUsername, AppUserEntity appUserEntity) {
15 | super(source);
16 | this.oldUsername = oldUsername;
17 | this.appUserEntity = appUserEntity;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/model/AppInviteEntity.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 |
5 | import javax.validation.constraints.Email;
6 | import javax.validation.constraints.NotNull;
7 | import java.time.Instant;
8 | import java.util.List;
9 |
10 | public interface AppInviteEntity extends EntityWithKeyValue, HasFirstAndLastName {
11 |
12 | String getId();
13 |
14 | void setId(String id);
15 |
16 | String getInvitor();
17 |
18 | void setInvitor(@NotNull String invitor);
19 |
20 | String getMessage();
21 |
22 | void setMessage(String message);
23 |
24 | String getFirstName();
25 |
26 | void setFirstName(String firstName);
27 |
28 | String getLastName();
29 |
30 | void setLastName(String lastName);
31 |
32 | String getEmail();
33 |
34 | void setEmail(@NotNull @Email String email);
35 |
36 | List getRoles();
37 |
38 | void setRoles(List roles);
39 |
40 | Instant getCreated();
41 |
42 | Instant getExpiration();
43 |
44 | void setExpiration(@NotNull Instant expiration);
45 |
46 | /**
47 | * fullname fallback if null use email
48 | */
49 | @JsonIgnore
50 | default String getDisplayName() {
51 | String fullName = getFullName();
52 | if (fullName == null) {
53 | return getEmail();
54 | }
55 | return fullName;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/model/EntityWithKeyValue.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model;
2 |
3 | import org.springframework.util.Assert;
4 |
5 | public interface EntityWithKeyValue extends HasKeyValue {
6 |
7 | /**
8 | * @param key max length of 50 characters
9 | * key with _ as prefix will not get displayed in REST_API
10 | * key with # as prefix will not get rendered within jwt-token but in userDto
11 | * @param value max length of 4000 characters
12 | * @return itself for fluent api
13 | */
14 | default T addKeyValue(String key, String value) {
15 | checkKeyValue(key, value);
16 | getKeyValues().put(key, value);
17 | return (T) this;
18 | }
19 |
20 | default void removeKeyValue(String key) {
21 | getKeyValues().remove(key);
22 | }
23 |
24 | default void checkKeyValue(String key, String value) {
25 | Assert.hasLength(key, "Key must not be empty");
26 | Assert.state(key.length() <= 50, "Key is too long - at least 50 chars");
27 | Assert.state(key.matches("[a-zA-Z0-9_\\-\\.\\#]+"), "Allowed key chars are a-Z, 0-9 and _-.#");
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/security/CommonsAuthenticationToken.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.security;
2 |
3 | import io.rocketbase.commons.model.AppUserToken;
4 | import io.rocketbase.commons.util.JwtTokenStore;
5 | import lombok.Getter;
6 | import org.springframework.security.authentication.AbstractAuthenticationToken;
7 | import org.springframework.security.core.GrantedAuthority;
8 |
9 | import java.util.Collection;
10 |
11 | public class CommonsAuthenticationToken extends AbstractAuthenticationToken {
12 |
13 | @Getter
14 | private final CommonsPrincipal principal;
15 |
16 | @Getter
17 | private final JwtTokenStore jwtTokenStore;
18 |
19 | public CommonsAuthenticationToken(Collection extends GrantedAuthority> authorities, AppUserToken appUserToken, JwtTokenStore jwtTokenStore) {
20 | super(authorities);
21 | this.principal = new CommonsPrincipal(appUserToken);
22 | this.jwtTokenStore = jwtTokenStore;
23 | }
24 |
25 | @Override
26 | public Object getCredentials() {
27 | return jwtTokenStore.getTokenBundle();
28 | }
29 |
30 | /**
31 | * shortcut for username of token
32 | */
33 | public String getUsername() {
34 | return principal.getUsername();
35 | }
36 |
37 | /**
38 | * shortcut for id of token
39 | */
40 | public String getId() {
41 | return principal.getId();
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/security/CustomAuthoritiesProvider.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.security;
2 |
3 | import io.rocketbase.commons.model.AppUserToken;
4 | import org.springframework.security.core.GrantedAuthority;
5 |
6 | import javax.servlet.http.HttpServletRequest;
7 | import java.util.Collection;
8 |
9 | /**
10 | * provide extra authorities apart from the general user-roles stored in db
11 | */
12 | public interface CustomAuthoritiesProvider {
13 |
14 | /**
15 | * will get injected in case of jwt-token creation
16 | * that means they are also present in case of SecurityContext
17 | * this should be considered for nearly static authorities that don't switch during a session
18 | *
19 | * @return a not nullable list of extra authorities / could also be an empty list
20 | */
21 | Collection extends GrantedAuthority> getExtraTokenAuthorities(AppUserToken user);
22 |
23 | /**
24 | * will get injected in case of SecurityContext initialization
25 | * you will find it in the security filter {@link io.rocketbase.commons.filter.JwtAuthenticationTokenFilter}
26 | * this should be considered for nearly dynamic authorities
27 | * keep in mind that also the extra token authorities will be present already
28 | *
29 | * @return a not nullable list of extra authorities / could also be an empty list
30 | */
31 | Collection extends GrantedAuthority> getExtraSecurityContextAuthorities(AppUserToken user, HttpServletRequest request);
32 | }
33 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/security/EmptyCustomAuthoritiesProvider.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.security;
2 |
3 | import io.rocketbase.commons.model.AppUserToken;
4 | import org.springframework.security.core.GrantedAuthority;
5 |
6 | import javax.servlet.http.HttpServletRequest;
7 | import java.util.Collection;
8 | import java.util.Collections;
9 |
10 | /**
11 | * default implementation of {@link CustomAuthoritiesProvider}
12 | */
13 | public class EmptyCustomAuthoritiesProvider implements CustomAuthoritiesProvider {
14 |
15 | @Override
16 | public Collection extends GrantedAuthority> getExtraTokenAuthorities(AppUserToken user) {
17 | return Collections.emptyList();
18 | }
19 |
20 | @Override
21 | public Collection extends GrantedAuthority> getExtraSecurityContextAuthorities(AppUserToken user, HttpServletRequest request) {
22 | return Collections.emptyList();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/AppInvitePersistenceService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service;
2 |
3 | import io.rocketbase.commons.dto.appinvite.QueryAppInvite;
4 | import io.rocketbase.commons.model.AppInviteEntity;
5 | import org.springframework.data.domain.Page;
6 | import org.springframework.data.domain.Pageable;
7 |
8 | import java.util.Optional;
9 |
10 | public interface AppInvitePersistenceService {
11 |
12 | Page findAll(QueryAppInvite query, Pageable pageable);
13 |
14 | S save(S entity);
15 |
16 | Optional findById(String id);
17 |
18 | long count();
19 |
20 | void delete(S entity);
21 |
22 | void deleteAll();
23 |
24 | S initNewInstance();
25 |
26 | long deleteExpired();
27 | }
28 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/AppUserPersistenceService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service;
2 |
3 | import io.rocketbase.commons.dto.appuser.QueryAppUser;
4 | import io.rocketbase.commons.model.AppUserEntity;
5 | import org.springframework.data.domain.Page;
6 | import org.springframework.data.domain.Pageable;
7 |
8 | import java.util.Optional;
9 |
10 | public interface AppUserPersistenceService {
11 |
12 | Optional findByUsername(String username);
13 |
14 | Optional findByEmail(String email);
15 |
16 | Page findAll(QueryAppUser query, Pageable pageable);
17 |
18 | S save(S entity);
19 |
20 | Optional findById(String id);
21 |
22 | long count();
23 |
24 | void delete(S entity);
25 |
26 | void deleteAll();
27 |
28 | S initNewInstance();
29 | }
30 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/JwtTokenStoreProvider.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service;
2 |
3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
4 | import io.rocketbase.commons.util.JwtTokenStore;
5 |
6 | public interface JwtTokenStoreProvider {
7 |
8 | JwtTokenStore getInstance(JwtTokenBundle tokenBundle);
9 | }
10 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/KeyGenerator.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service;
2 |
3 | import java.security.SecureRandom;
4 |
5 | public final class KeyGenerator {
6 |
7 | private static final String ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
8 | private static final String SPECIAL_SIGN = "!#$%&()*+,-./:;<=>?@[]^_`{|}~";
9 | private static final String ALPHABET_WITH_SPECIAL = ALPHABET + SPECIAL_SIGN;
10 | private static SecureRandom RANDOM = new SecureRandom();
11 |
12 | /**
13 | * random string with alphabet of 0-9 + a-z (lower/upper)
14 | *
15 | * @param length of string
16 | * @return random string
17 | */
18 | public static String random(int length) {
19 | StringBuilder sb = new StringBuilder(length);
20 | for (int i = 0; i < length; i++)
21 | sb.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length())));
22 | return sb.toString();
23 | }
24 |
25 | /**
26 | * random string with alphabet of 0-9 + a-z (lower/upper)
27 | * plus special sings of "!#$%&()*+,-./:;<=>?@[]^_`{|}~"
28 | *
29 | * @param length of string
30 | * @return random string
31 | */
32 | public static String randomWithSpecialSigns(int length) {
33 | StringBuilder sb = new StringBuilder(length);
34 | for (int i = 0; i < length; i++)
35 | sb.append(ALPHABET_WITH_SPECIAL.charAt(RANDOM.nextInt(ALPHABET_WITH_SPECIAL.length())));
36 | return sb.toString();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/ValidationUserLookupService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service;
2 |
3 | import io.rocketbase.commons.model.AppUserEntity;
4 | import io.rocketbase.commons.model.AppUserToken;
5 |
6 | import java.util.Optional;
7 |
8 | public interface ValidationUserLookupService {
9 |
10 | AppUserToken getByUsername(String username);
11 |
12 | Optional findByEmail(String email);
13 | }
14 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/avatar/AvatarService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.avatar;
2 |
3 | public interface AvatarService {
4 |
5 | String getAvatar(String email);
6 |
7 | boolean isEnabled();
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/avatar/GravatarService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.avatar;
2 |
3 | import io.rocketbase.commons.config.GravatarProperties;
4 | import lombok.RequiredArgsConstructor;
5 | import lombok.SneakyThrows;
6 | import org.springframework.web.util.UriComponentsBuilder;
7 |
8 | import javax.xml.bind.DatatypeConverter;
9 | import java.security.MessageDigest;
10 |
11 | @RequiredArgsConstructor
12 | public class GravatarService implements AvatarService {
13 |
14 | final GravatarProperties gravatarProperties;
15 |
16 | @Override
17 | public String getAvatar(String email) {
18 | if (email == null) {
19 | return null;
20 | }
21 | UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString("https://www.gravatar.com/avatar/");
22 | uriBuilder.path(md5(email.toLowerCase()));
23 | uriBuilder.path(".jpg");
24 | uriBuilder.queryParam("s", gravatarProperties.getSize());
25 | uriBuilder.queryParam("d", gravatarProperties.getImage().getUrlParam());
26 | if (gravatarProperties.getRating() != null) {
27 | uriBuilder.queryParam("r", gravatarProperties.getRating().getUrlParam());
28 | }
29 | return uriBuilder.toUriString();
30 | }
31 |
32 | @SneakyThrows
33 | private String md5(String text) {
34 | MessageDigest md = MessageDigest.getInstance("MD5");
35 | md.update((text == null ? "" : text).getBytes());
36 | return DatatypeConverter.printHexBinary(md.digest()).toLowerCase();
37 | }
38 |
39 | @Override
40 | public boolean isEnabled() {
41 | return gravatarProperties.isEnabled();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/email/AuthEmailService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.email;
2 |
3 | import io.rocketbase.commons.model.AppInviteEntity;
4 | import io.rocketbase.commons.model.AppUserReference;
5 |
6 | public interface AuthEmailService {
7 |
8 | void sentRegistrationEmail(AppUserReference user, String verificationUrl);
9 |
10 | void sentForgotPasswordEmail(AppUserReference user, String verificationUrl);
11 |
12 | void sentInviteEmail(AppInviteEntity invite, String verificationUrl);
13 |
14 | void sentChangeEmailAddressEmail(AppUserReference user, String newEmailAddress, String verificationUrl);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/email/EmailAddress.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.email;
2 |
3 | import lombok.Getter;
4 | import lombok.RequiredArgsConstructor;
5 |
6 | import javax.annotation.Nullable;
7 | import javax.validation.ConstraintViolation;
8 | import javax.validation.Validation;
9 | import javax.validation.ValidatorFactory;
10 | import javax.validation.constraints.Email;
11 | import javax.validation.constraints.NotNull;
12 | import java.util.Set;
13 |
14 | @Getter
15 | @RequiredArgsConstructor
16 | public class EmailAddress {
17 |
18 | @NotNull
19 | @Email
20 | private final String email;
21 |
22 | @Nullable
23 | private final String name;
24 |
25 | public EmailAddress(String email) {
26 | this.email = email;
27 | this.name = null;
28 | }
29 |
30 | public boolean isValid() {
31 | ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
32 | Set> validate = factory.getValidator().validate(this);
33 | return validate == null || validate.isEmpty();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/email/EmailLogSender.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.email;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 |
5 | @Slf4j
6 | public class EmailLogSender implements EmailSender {
7 |
8 | @Override
9 | public void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from) {
10 | log.warn("sentEmail to: {}, subject: {}", to.getEmail(), subject);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/email/EmailSender.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.email;
2 |
3 | public interface EmailSender {
4 |
5 | void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from);
6 | }
7 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/service/user/ActiveUserStore.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.user;
2 |
3 | import io.rocketbase.commons.model.AppUserToken;
4 |
5 | import java.util.Set;
6 |
7 | public interface ActiveUserStore {
8 | void addUser(AppUserToken user);
9 |
10 | void clear();
11 |
12 | long getUserCount();
13 |
14 | Set getUserIds();
15 | }
16 |
--------------------------------------------------------------------------------
/commons-auth-core/src/main/java/io/rocketbase/commons/util/RolesAuthoritiesConverter.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.util;
2 |
3 | import org.springframework.security.core.GrantedAuthority;
4 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Collection;
8 | import java.util.Collections;
9 | import java.util.List;
10 | import java.util.stream.Collectors;
11 |
12 | public final class RolesAuthoritiesConverter {
13 |
14 | /**
15 | * converts a list of roles into a collection of GrantedAuthority
16 | *
17 | * @return never null
18 | */
19 | public static Collection extends GrantedAuthority> convert(List roles) {
20 | return roles != null ?
21 | roles.stream()
22 | .map(r -> new SimpleGrantedAuthority(String.format("ROLE_%s", r.replaceAll("^ROLE_", ""))))
23 | .collect(Collectors.toList()) :
24 | Collections.emptyList();
25 | }
26 |
27 | /**
28 | * converts a collection of authorities into a list of roles
29 | *
30 | * @return never null
31 | */
32 | public static List convertToDtos(Collection extends GrantedAuthority> authorities) {
33 | return authorities != null ?
34 | new ArrayList<>(authorities.stream()
35 | .filter(r -> r.getAuthority() != null)
36 | .map(r -> r.getAuthority())
37 | .collect(Collectors.toSet())) :
38 | Collections.emptyList();
39 | }
40 |
41 | /**
42 | * converts a collection of roles into a list of roles
43 | *
44 | * @return never null
45 | */
46 | public static List convertRoles(List roles) {
47 | return roles != null ?
48 | new ArrayList<>(roles.stream()
49 | .map(r -> String.format("ROLE_%s", r.replaceAll("^ROLE_", "")))
50 | .collect(Collectors.toSet())) :
51 | Collections.emptyList();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/commons-auth-core/src/test/java/io/rocketbase/commons/service/GravatarServiceTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service;
2 |
3 | import io.rocketbase.commons.config.GravatarProperties;
4 | import io.rocketbase.commons.service.avatar.GravatarService;
5 | import org.junit.Test;
6 |
7 | import static org.hamcrest.MatcherAssert.assertThat;
8 | import static org.hamcrest.Matchers.*;
9 |
10 | public class GravatarServiceTest {
11 |
12 | @Test
13 | public void getAvatar() {
14 | // given
15 | String email = "marten@rocketbase.io";
16 |
17 | // when
18 | String imageUrl = new GravatarService(getGravatarConfiguration()).getAvatar(email);
19 |
20 | // then
21 | assertThat(imageUrl, notNullValue());
22 | assertThat(imageUrl, equalTo("https://www.gravatar.com/avatar/fc40e22b7bcd7230b49c34eb113d5dbc.jpg?s=160&d=robohash"));
23 | }
24 |
25 | @Test
26 | public void nullAvatar() {
27 | // given
28 | String email = null;
29 |
30 | // when
31 | String imageUrl = new GravatarService(getGravatarConfiguration()).getAvatar(email);
32 |
33 | // then
34 | assertThat(imageUrl, nullValue());
35 | }
36 |
37 | private GravatarProperties getGravatarConfiguration() {
38 | GravatarProperties gravatarProperties = new GravatarProperties();
39 | gravatarProperties.setSize(160);
40 | gravatarProperties.setImage(GravatarProperties.DefaultImage.ROBOHASH);
41 | return gravatarProperties;
42 | }
43 | }
--------------------------------------------------------------------------------
/commons-auth-core/src/test/java/io/rocketbase/commons/service/user/ActiveUserStoreLocalCacheTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.user;
2 |
3 | import io.rocketbase.commons.model.SimpleAppUserToken;
4 | import org.junit.Test;
5 | import org.springframework.context.ApplicationEventPublisher;
6 |
7 | import java.util.Arrays;
8 |
9 | import static org.hamcrest.MatcherAssert.assertThat;
10 | import static org.hamcrest.Matchers.equalTo;
11 |
12 | public class ActiveUserStoreLocalCacheTest {
13 |
14 | @Test
15 | public void shouldRemoveInvalided() throws Exception {
16 | // given
17 | ActiveUserStoreLocalCache activeUserStore = new ActiveUserStoreLocalCache(150);
18 | activeUserStore.applicationEventPublisher = new ApplicationEventPublisher() {
19 | @Override
20 | public void publishEvent(Object event) {
21 |
22 | }
23 | };
24 | // when
25 | activeUserStore.addUser(new SimpleAppUserToken("1", "user-1", Arrays.asList("TEST")));
26 | activeUserStore.addUser(new SimpleAppUserToken("2", "user-2", Arrays.asList("TEST")));
27 |
28 | // then
29 | assertThat(activeUserStore.getUserCount(), equalTo(2L));
30 |
31 | // when
32 | Thread.sleep(200);
33 | activeUserStore.addUser(new SimpleAppUserToken("1", "user-1", Arrays.asList("TEST")));
34 | assertThat(activeUserStore.getUserCount(), equalTo(1L));
35 |
36 | // when
37 | Thread.sleep(200);
38 | assertThat(activeUserStore.getUserCount(), equalTo(0L));
39 | }
40 | }
--------------------------------------------------------------------------------
/commons-auth-core/src/test/resources/application-test.yml:
--------------------------------------------------------------------------------
1 | logging:
2 | level:
3 | io.rocketbase: TRACE
4 |
5 | # auth configuration
6 | auth:
7 | jwt:
8 | secret: 'P0UoSCtNYlBlU2hWbVlxM3Q2dzl6JEMmRilKQE5jUmZUalduWnI0dTd4IUElRCpHLUthUGRTZ1ZrWHAyczV2OA=='
9 | user-cache-time: 0
--------------------------------------------------------------------------------
/commons-auth-email-postmark/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | commons-auth
7 | io.rocketbase.commons
8 | LATEST-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | commons-auth-email-postmark
13 |
14 |
15 |
16 | io.rocketbase.commons
17 | commons-auth-core
18 | ${project.version}
19 |
20 |
21 | io.rocketbase.mail
22 | postmark-spring
23 | ${postmark-spring.version}
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/commons-auth-email-postmark/src/main/java/io/rocketbase/commons/config/AuthEmailPostmarkAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import io.rocketbase.commons.service.email.EmailPostmarkSender;
4 | import io.rocketbase.commons.service.email.EmailSender;
5 | import io.rocketbase.mail.PostmarkClient;
6 | import lombok.RequiredArgsConstructor;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 |
11 | @Configuration
12 | @RequiredArgsConstructor
13 | public class AuthEmailPostmarkAutoConfiguration {
14 |
15 | @Bean
16 | public EmailSender emailSender(@Autowired PostmarkClient postmarkClient) {
17 | return new EmailPostmarkSender(postmarkClient);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/commons-auth-email-postmark/src/main/java/io/rocketbase/commons/service/email/EmailPostmarkSender.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.email;
2 |
3 | import io.rocketbase.mail.PostmarkClient;
4 | import io.rocketbase.mail.dto.Message;
5 | import io.rocketbase.mail.dto.MessageResponse;
6 | import lombok.RequiredArgsConstructor;
7 | import lombok.SneakyThrows;
8 |
9 | @RequiredArgsConstructor
10 | public class EmailPostmarkSender implements EmailSender {
11 |
12 | private final PostmarkClient postmarkClient;
13 |
14 | @SneakyThrows
15 | @Override
16 | public void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from) {
17 | Message message = new Message();
18 | message.setFrom(convert(from));
19 | message.setTo(convert(to));
20 | message.setSubject(subject);
21 | message.setHtmlBody(html);
22 | message.setTextBody(text);
23 |
24 | MessageResponse response = postmarkClient.deliverMessage(message);
25 | }
26 |
27 | protected io.rocketbase.mail.dto.EmailAddress convert(EmailAddress mail) {
28 | return new io.rocketbase.mail.dto.EmailAddress(mail.getEmail(), mail.getName());
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/commons-auth-email-postmark/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | io.rocketbase.commons.config.AuthEmailPostmarkAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-email-postmark/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
--------------------------------------------------------------------------------
1 | io.rocketbase.commons.config.AuthEmailPostmarkAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-email-smtp/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | commons-auth
7 | io.rocketbase.commons
8 | LATEST-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | commons-auth-email-smtp
13 |
14 |
15 |
16 | io.rocketbase.commons
17 | commons-auth-core
18 | ${project.version}
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-mail
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-autoconfigure
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/commons-auth-email-smtp/src/main/java/io/rocketbase/commons/config/AuthEmailSmtpAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import io.rocketbase.commons.service.email.EmailSender;
4 | import io.rocketbase.commons.service.email.EmailSmtpSender;
5 | import lombok.RequiredArgsConstructor;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.mail.javamail.JavaMailSender;
10 |
11 | @Configuration
12 | @RequiredArgsConstructor
13 | public class AuthEmailSmtpAutoConfiguration {
14 |
15 | @Bean
16 | public EmailSender emailSender(@Autowired JavaMailSender javaMailSender) {
17 | return new EmailSmtpSender(javaMailSender);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/commons-auth-email-smtp/src/main/java/io/rocketbase/commons/service/email/EmailSmtpSender.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.email;
2 |
3 | import lombok.RequiredArgsConstructor;
4 | import lombok.SneakyThrows;
5 | import org.springframework.mail.javamail.JavaMailSender;
6 | import org.springframework.mail.javamail.MimeMessageHelper;
7 |
8 | import javax.mail.internet.InternetAddress;
9 | import javax.mail.internet.MimeMessage;
10 | import java.nio.charset.StandardCharsets;
11 |
12 | @RequiredArgsConstructor
13 | public class EmailSmtpSender implements EmailSender {
14 |
15 | private final JavaMailSender emailSender;
16 |
17 | @SneakyThrows
18 | @Override
19 | public void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from) {
20 | MimeMessage message = emailSender.createMimeMessage();
21 | MimeMessageHelper helper = new MimeMessageHelper(message,
22 | MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
23 | StandardCharsets.UTF_8.name());
24 | helper.setTo(convert(to));
25 | helper.setSubject(subject);
26 | helper.setText(text, html);
27 | helper.setFrom(convert(from));
28 | emailSender.send(message);
29 | }
30 |
31 | @SneakyThrows
32 | protected InternetAddress convert(EmailAddress email) {
33 | return new InternetAddress(email.getEmail(), email.getName());
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/commons-auth-email-smtp/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | io.rocketbase.commons.config.AuthEmailSmtpAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-email-smtp/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
--------------------------------------------------------------------------------
1 | io.rocketbase.commons.config.AuthEmailSmtpAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/java/io/rocketbase/commons/controller/AbstractFormsController.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller;
2 |
3 | import io.rocketbase.commons.config.FormsProperties;
4 | import io.rocketbase.commons.config.RegistrationProperties;
5 | import lombok.Getter;
6 | import org.springframework.ui.Model;
7 | import org.springframework.web.bind.annotation.ModelAttribute;
8 |
9 | public abstract class AbstractFormsController {
10 |
11 | @Getter
12 | private final FormsProperties formsProperties;
13 | @Getter
14 | private final RegistrationProperties registrationProperties;
15 |
16 | public AbstractFormsController(FormsProperties formsProperties, RegistrationProperties registrationProperties) {
17 | this.formsProperties = formsProperties;
18 | this.registrationProperties = registrationProperties;
19 | }
20 |
21 | @ModelAttribute
22 | public void populateDefaults(Model model) {
23 | model.addAttribute("title", formsProperties.getTitle());
24 | model.addAttribute("logoSrc", formsProperties.getLogoSrc());
25 | model.addAttribute("registrationEnabled", registrationProperties.isEnabled());
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/java/io/rocketbase/commons/controller/VerifyChangeFormsController.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller;
2 |
3 | import io.rocketbase.commons.api.AuthenticationApi;
4 | import io.rocketbase.commons.config.FormsProperties;
5 | import io.rocketbase.commons.config.RegistrationProperties;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.springframework.stereotype.Controller;
8 | import org.springframework.ui.Model;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.RequestParam;
11 |
12 | @Slf4j
13 | @Controller
14 | public class VerifyChangeFormsController extends AbstractFormsController {
15 |
16 | private final AuthenticationApi authenticationApi;
17 |
18 | public VerifyChangeFormsController(FormsProperties formsProperties, RegistrationProperties registrationProperties, AuthenticationApi authenticationApi) {
19 | super(formsProperties, registrationProperties);
20 | this.authenticationApi = authenticationApi;
21 | }
22 |
23 | @GetMapping("${auth.forms.prefix:}/verify-email")
24 | public String verify(@RequestParam(value = "verification", required = false) String verification, Model model) {
25 | try {
26 | authenticationApi.verifyEmail(verification);
27 | model.addAttribute("valid", true);
28 | } catch (Exception e) {
29 | model.addAttribute("valid", false);
30 | }
31 | return "email-change-success";
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/META-INF/resources/assets/commons-auth.css:
--------------------------------------------------------------------------------
1 | @import url("https://cdnjs.cloudflare.com/ajax/libs/bulma/1.0.2/css/bulma.min.css");
2 | @import url("https://fonts.googleapis.com/css?family=Open+Sans:300,700&display=swap");
3 |
4 | html, body {
5 | font-family: 'Open Sans', serif;
6 | font-size: 14px;
7 | font-weight: 300;
8 | }
9 |
10 | .hero {
11 | background: #fafafa;
12 | -webkit-box-shadow: none;
13 | box-shadow: none;
14 | }
15 |
16 | .box {
17 | margin-top: 5rem;
18 | }
19 |
20 | .avatar {
21 | margin: -70px auto 20px auto;
22 | padding: 7px;
23 | background: #fff;
24 | width: 142px;
25 | height: 142px;
26 | border-radius: 50%;
27 | -webkit-box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
28 | box-shadow: 0 2px 3px rgba(10, 10, 10, .1), 0 0 0 1px rgba(10, 10, 10, .1);
29 | }
30 |
31 | input {
32 | font-weight: 300;
33 | }
34 |
35 | p {
36 | font-weight: 700;
37 | }
38 | p.light {
39 | font-weight: 300;
40 | }
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | io.rocketbase.commons.config.AuthFormAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
--------------------------------------------------------------------------------
1 | io.rocketbase.commons.config.AuthFormAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/templates/email-change-success.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Successfully changed email-adress *Yeah*
28 |
Your old email-adress will not get used any longer.
29 |
30 |
31 |
32 |
33 |
34 | Verification is expired please request a new email-change to get a valid link!
35 |
36 |
37 |
38 |
39 |
40 | Login
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/templates/forgot-submitted.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | Successfully requested password reset
25 |
26 |
27 |
28 | You need to check your mailbox. Via the link you can change your password within X minutes.
29 |
30 |
31 |
32 | Login
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/templates/invite-success.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Successfully created account *Yeah*
24 |
25 | You can now use the application with your account username.
26 |
27 |
28 |
29 | Login
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/templates/registration-success.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Successfully registered *Yeah*
24 |
25 | You need to verify your email. Please check your mailbox! Via the link you can confirm your registration within X minutes.
26 |
27 |
28 | You can now use the application.
29 |
30 |
31 |
32 | Login
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/templates/registration-verification.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
Successfully verified *Yeah*
25 |
You can start using the app.
26 |
27 |
28 |
Could not verify your registration.
29 |
Please retry or contact the adminstrator./
30 |
31 |
32 |
33 | Login
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/commons-auth-forms/src/main/resources/templates/reset-password-success.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Successfully changed password *Yeah*
26 |
27 |
28 |
29 | You can now login to the application again.
30 |
31 |
32 |
33 | Login
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/commons-auth-jpa/src/main/java/io/rocketbase/commons/config/AuthJpaAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import io.rocketbase.commons.model.AppInviteJpaEntity;
4 | import io.rocketbase.commons.model.AppUserJpaEntity;
5 | import io.rocketbase.commons.repository.AppInviteJpaRepository;
6 | import io.rocketbase.commons.repository.AppUserJpaRepository;
7 | import io.rocketbase.commons.service.AppInviteJpaServiceImpl;
8 | import io.rocketbase.commons.service.AppInvitePersistenceService;
9 | import io.rocketbase.commons.service.AppUserJpaServiceImpl;
10 | import io.rocketbase.commons.service.AppUserPersistenceService;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
13 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
14 | import org.springframework.context.annotation.Bean;
15 | import org.springframework.context.annotation.Configuration;
16 |
17 | @Configuration
18 | @AutoConfigureBefore(AuthServiceAutoConfiguration.class)
19 | public class AuthJpaAutoConfiguration {
20 |
21 | @Bean
22 | @ConditionalOnMissingBean
23 | public AppUserPersistenceService appUserPersistenceService(@Autowired AppUserJpaRepository appUserJpaRepository) {
24 | return new AppUserJpaServiceImpl(appUserJpaRepository);
25 | }
26 |
27 | @Bean
28 | @ConditionalOnMissingBean
29 | public AppInvitePersistenceService appInvitePersistenceService(@Autowired AppInviteJpaRepository appInviteJpaRepository) {
30 | return new AppInviteJpaServiceImpl(appInviteJpaRepository);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/commons-auth-jpa/src/main/java/io/rocketbase/commons/model/AppInviteJpaEntity.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model;
2 |
3 | import io.rocketbase.commons.model.converter.StringListConverter;
4 | import lombok.*;
5 | import org.springframework.data.annotation.CreatedDate;
6 |
7 | import javax.persistence.*;
8 | import java.time.Instant;
9 | import java.util.HashMap;
10 | import java.util.List;
11 | import java.util.Map;
12 |
13 |
14 | @Entity
15 | @Table(name = "co_invite")
16 | @Data
17 | @Builder
18 | @AllArgsConstructor
19 | @NoArgsConstructor
20 | @EqualsAndHashCode(of = {"id"})
21 | public class AppInviteJpaEntity implements AppInviteEntity {
22 |
23 | @Id
24 | @Column(length = 36, nullable = false)
25 | private String id;
26 |
27 | private String invitor;
28 |
29 | @Column(length = 4000)
30 | private String message;
31 |
32 | private String firstName;
33 |
34 | private String lastName;
35 |
36 | private String email;
37 |
38 | @Column(name = "roles")
39 | @Convert(converter = StringListConverter.class)
40 | private List roles;
41 |
42 | @ElementCollection
43 | @CollectionTable(
44 | name = "co_invite_keyvalue",
45 | joinColumns = @JoinColumn(name = "invite_id"),
46 | uniqueConstraints = @UniqueConstraint(name = "uk_invite_keyvalue", columnNames = {"invite_id", "field_key"}),
47 | indexes = @Index(name = "idx_invite_keyvalue", columnList = "invite_id")
48 | )
49 | @MapKeyColumn(name = "field_key", length = 50)
50 | @Column(name = "field_value", nullable = false)
51 | @Builder.Default
52 | private Map keyValueMap = new HashMap<>();
53 |
54 | @CreatedDate
55 | @Column(nullable = false)
56 | private Instant created;
57 |
58 | @Column(nullable = false)
59 | private Instant expiration;
60 |
61 | @Override
62 | public Map getKeyValues() {
63 | return keyValueMap;
64 | }
65 |
66 | @Override
67 | public void setKeyValues(Map map) {
68 | this.keyValueMap = map;
69 | }
70 |
71 | public AppInviteJpaEntity(String id) {
72 | this.id = id;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/commons-auth-jpa/src/main/java/io/rocketbase/commons/model/converter/StringListConverter.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model.converter;
2 |
3 | import com.google.common.base.Joiner;
4 | import com.google.common.base.Splitter;
5 | import com.google.common.collect.Lists;
6 | import org.springframework.util.StringUtils;
7 |
8 | import javax.persistence.AttributeConverter;
9 | import javax.persistence.Convert;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | @Convert
14 | public class StringListConverter implements AttributeConverter, String> {
15 |
16 | @Override
17 | public String convertToDatabaseColumn(List attribute) {
18 | String result = null;
19 | if (attribute != null) {
20 | result = Joiner.on(";").join(attribute);
21 | }
22 | return result;
23 | }
24 |
25 | @Override
26 | public List convertToEntityAttribute(String dbData) {
27 | List result = new ArrayList<>();
28 | if (!StringUtils.isEmpty(dbData)) {
29 | result = Lists.newArrayList(Splitter.on(";").split(dbData));
30 | }
31 | return result;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/commons-auth-jpa/src/main/java/io/rocketbase/commons/repository/AppInviteJpaRepository.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.repository;
2 |
3 | import io.rocketbase.commons.model.AppInviteJpaEntity;
4 | import org.springframework.data.domain.Page;
5 | import org.springframework.data.domain.Pageable;
6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
7 | import org.springframework.data.jpa.repository.Query;
8 | import org.springframework.data.repository.PagingAndSortingRepository;
9 | import org.springframework.data.repository.query.Param;
10 | import org.springframework.data.repository.query.QueryByExampleExecutor;
11 |
12 | import java.util.Optional;
13 |
14 | public interface AppInviteJpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor, JpaSpecificationExecutor {
15 |
16 | @Query("select a from AppInviteJpaEntity a left join fetch a.keyValueMap where a.id = :id")
17 | Optional findById(@Param("id") String id);
18 |
19 | @Query(value = "select a from AppInviteJpaEntity a left join fetch a.keyValueMap",
20 | countQuery = "select count(a) from AppInviteJpaEntity a")
21 | Page findAll(Pageable pageable);
22 | }
23 |
--------------------------------------------------------------------------------
/commons-auth-jpa/src/main/java/io/rocketbase/commons/repository/AppUserJpaRepository.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.repository;
2 |
3 | import io.rocketbase.commons.model.AppUserJpaEntity;
4 | import org.springframework.data.domain.Page;
5 | import org.springframework.data.domain.Pageable;
6 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
7 | import org.springframework.data.jpa.repository.Query;
8 | import org.springframework.data.repository.PagingAndSortingRepository;
9 | import org.springframework.data.repository.query.Param;
10 | import org.springframework.data.repository.query.QueryByExampleExecutor;
11 |
12 | import java.util.Optional;
13 |
14 | public interface AppUserJpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor, JpaSpecificationExecutor {
15 |
16 | @Query("select a from AppUserJpaEntity a left join fetch a.keyValueMap left join fetch a.roles where a.id = :id")
17 | Optional findById(@Param("id") String id);
18 |
19 | @Query("select a from AppUserJpaEntity a left join fetch a.keyValueMap left join fetch a.roles where a.username = :username")
20 | Optional findByUsername(@Param("username") String username);
21 |
22 | @Query("select a from AppUserJpaEntity a left join fetch a.keyValueMap left join fetch a.roles where a.email = :email")
23 | Optional findByEmail(@Param("email") String email);
24 |
25 | @Query(value = "select a from AppUserJpaEntity a left join fetch a.keyValueMap left join fetch a.roles",
26 | countQuery = "select count(a) from AppUserJpaEntity a")
27 | Page findAll(Pageable pageable);
28 | }
29 |
--------------------------------------------------------------------------------
/commons-auth-jpa/src/main/java/io/rocketbase/commons/service/PredicateHelper.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service;
2 |
3 | import org.springframework.util.StringUtils;
4 |
5 | import javax.persistence.criteria.CriteriaBuilder;
6 | import javax.persistence.criteria.Predicate;
7 | import javax.persistence.criteria.Root;
8 | import java.util.List;
9 |
10 | public interface PredicateHelper {
11 |
12 | default String buildLikeString(String value) {
13 | if (value.contains("*") || value.contains("%")) {
14 | return value.trim().toLowerCase().replace("*", "%");
15 | }
16 | return "%" + value.trim().toLowerCase() + "%";
17 | }
18 |
19 | default void addToListIfNotEmpty(List list, String value, String path, Root root, CriteriaBuilder cb) {
20 | if (!StringUtils.isEmpty(value)) {
21 | list.add(cb.like(cb.lower(root.get(path)), buildLikeString(value)));
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/commons-auth-jpa/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | io.rocketbase.commons.config.AuthJpaAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-jpa/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
--------------------------------------------------------------------------------
1 | io.rocketbase.commons.config.AuthJpaAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-jpa/src/test/java/io/rocketbase/commons/Application.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class Application {
8 |
9 |
10 | public static void main(String[] args) throws Exception {
11 | SpringApplication.run(Application.class, args);
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/commons-auth-jpa/src/test/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | datasource:
3 | driver-class-name: org.h2.Driver
4 | jdbc-url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
5 | username: sa
6 | password: sa
7 |
8 | main:
9 | allow-circular-references: true
10 |
11 | hibernate:
12 | dialect: org.hibernate.dialect.H2Dialect
13 | hbm2ddl:
14 | auto: create-drop
15 | show_sql: true
16 |
17 | logging:
18 | level:
19 | io.rocketbase: DEBUG
20 | org.hibernate:
21 | SQL: TRACE
22 | type.descriptor:.sql.BasicBinder: TRACE
23 |
--------------------------------------------------------------------------------
/commons-auth-mongo/src/main/java/io/rocketbase/commons/config/AuthMongoAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.config;
2 |
3 | import io.rocketbase.commons.model.AppInviteMongoEntity;
4 | import io.rocketbase.commons.model.AppUserMongoEntity;
5 | import io.rocketbase.commons.service.AppInviteMongoServiceImpl;
6 | import io.rocketbase.commons.service.AppInvitePersistenceService;
7 | import io.rocketbase.commons.service.AppUserMongoServiceImpl;
8 | import io.rocketbase.commons.service.AppUserPersistenceService;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.autoconfigure.AutoConfigureBefore;
11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
12 | import org.springframework.context.annotation.Bean;
13 | import org.springframework.context.annotation.Configuration;
14 | import org.springframework.data.mongodb.core.MongoTemplate;
15 |
16 | @Configuration
17 | @AutoConfigureBefore(AuthServiceAutoConfiguration.class)
18 | public class AuthMongoAutoConfiguration {
19 |
20 | @Bean
21 | @ConditionalOnMissingBean
22 | public AppUserPersistenceService appUserPersistenceService(@Autowired MongoTemplate mongoTemplate) {
23 | return new AppUserMongoServiceImpl(mongoTemplate);
24 | }
25 |
26 | @Bean
27 | @ConditionalOnMissingBean
28 | public AppInvitePersistenceService appInvitePersistenceService(@Autowired MongoTemplate mongoTemplate) {
29 | return new AppInviteMongoServiceImpl(mongoTemplate);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/commons-auth-mongo/src/main/java/io/rocketbase/commons/model/AppInviteMongoEntity.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.model;
2 |
3 | import lombok.*;
4 | import org.springframework.data.annotation.CreatedDate;
5 | import org.springframework.data.annotation.Id;
6 | import org.springframework.data.mongodb.core.index.Indexed;
7 | import org.springframework.data.mongodb.core.mapping.Document;
8 |
9 | import javax.validation.constraints.Email;
10 | import javax.validation.constraints.NotNull;
11 | import java.time.Instant;
12 | import java.util.HashMap;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 |
17 | @Document(collection = "invite")
18 | @Data
19 | @Builder
20 | @AllArgsConstructor
21 | @NoArgsConstructor
22 | @EqualsAndHashCode(of = {"id"})
23 | public class AppInviteMongoEntity implements AppInviteEntity {
24 |
25 | @Id
26 | private String id;
27 |
28 | @Indexed
29 | private String invitor;
30 |
31 | private String message;
32 |
33 | private String firstName;
34 |
35 | private String lastName;
36 |
37 | @NotNull
38 | @Email
39 | private String email;
40 |
41 | private List roles;
42 |
43 | @CreatedDate
44 | private Instant created;
45 |
46 | @Indexed
47 | private Instant expiration;
48 |
49 | @Builder.Default
50 | private Map keyValueMap = new HashMap<>();
51 |
52 | @Override
53 | public Map getKeyValues() {
54 | return keyValueMap;
55 | }
56 |
57 | @Override
58 | public void setKeyValues(Map map) {
59 | this.keyValueMap = map;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/commons-auth-mongo/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | io.rocketbase.commons.config.AuthMongoAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-mongo/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
--------------------------------------------------------------------------------
1 | io.rocketbase.commons.config.AuthMongoAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-mongo/src/test/java/io/rocketbase/commons/Application.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class Application {
8 |
9 |
10 | public static void main(String[] args) throws Exception {
11 | SpringApplication.run(Application.class, args);
12 | }
13 |
14 | }
--------------------------------------------------------------------------------
/commons-auth-mongo/src/test/java/io/rocketbase/commons/service/BaseIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service;
2 |
3 | import io.rocketbase.commons.Application;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.junit.runner.RunWith;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.test.context.DynamicPropertyRegistry;
8 | import org.springframework.test.context.DynamicPropertySource;
9 | import org.springframework.test.context.junit4.SpringRunner;
10 | import org.testcontainers.containers.MongoDBContainer;
11 | import org.testcontainers.junit.jupiter.Container;
12 | import org.testcontainers.junit.jupiter.Testcontainers;
13 | import org.testcontainers.utility.DockerImageName;
14 |
15 |
16 | @Slf4j
17 | @RunWith(SpringRunner.class)
18 | @SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
19 | @Testcontainers
20 | public abstract class BaseIntegrationTest {
21 | @Container
22 | protected static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4"));
23 |
24 | @DynamicPropertySource
25 | static void initTestContainerProperties(DynamicPropertyRegistry registry) {
26 | mongoDBContainer.start();
27 | log.info("Setting spring.data.mongodb.uri = {}", mongoDBContainer.getReplicaSetUrl());
28 | registry.add("spring.data.mongodb.uri", mongoDBContainer::getReplicaSetUrl);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/commons-auth-mongo/src/test/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | main:
3 | allow-circular-references: true
--------------------------------------------------------------------------------
/commons-auth-server/src/main/java/io/rocketbase/commons/controller/ImpersonateController.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller;
2 |
3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
4 | import io.rocketbase.commons.exception.NotFoundException;
5 | import io.rocketbase.commons.model.AppUserEntity;
6 | import io.rocketbase.commons.security.CommonsPrincipal;
7 | import io.rocketbase.commons.service.impersonate.ImpersonateService;
8 | import io.rocketbase.commons.service.user.ActiveUserStore;
9 | import io.rocketbase.commons.service.user.AppUserService;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
12 | import org.springframework.http.ResponseEntity;
13 | import org.springframework.web.bind.annotation.*;
14 |
15 | import javax.annotation.Resource;
16 |
17 | @Slf4j
18 | @RestController
19 | @ConditionalOnExpression(value = "${auth.impersonate.enabled:true}")
20 | @RequestMapping("${auth.prefix:}")
21 | public class ImpersonateController implements BaseController {
22 |
23 | @Resource
24 | private AppUserService appUserService;
25 |
26 | @Resource
27 | private ImpersonateService impersonateService;
28 |
29 | @Resource
30 | private ActiveUserStore activeUserStore;
31 |
32 | @RequestMapping(method = RequestMethod.GET, path = "/api/impersonate/{userIdOrUsername}")
33 | @ResponseBody
34 | public ResponseEntity impersonate(@PathVariable("userIdOrUsername") String userIdOrUsername) {
35 | AppUserEntity impersonateUser = appUserService.findByIdOrUsername(userIdOrUsername).orElseThrow(NotFoundException::new);
36 | activeUserStore.addUser(impersonateUser);
37 |
38 | return ResponseEntity.ok(impersonateService.getImpersonateBundle(CommonsPrincipal.getCurrent(), impersonateUser));
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/EmailValidationExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller.exceptionhandler;
2 |
3 | import io.rocketbase.commons.dto.ErrorResponse;
4 | import io.rocketbase.commons.dto.validation.EmailErrorCodes;
5 | import io.rocketbase.commons.exception.EmailValidationException;
6 | import io.rocketbase.commons.exception.ErrorCodes;
7 | import io.rocketbase.commons.exception.ValidationErrorCode;
8 | import io.rocketbase.commons.util.Nulls;
9 | import org.springframework.web.bind.annotation.ControllerAdvice;
10 | import org.springframework.web.bind.annotation.ExceptionHandler;
11 | import org.springframework.web.bind.annotation.ResponseBody;
12 | import org.springframework.web.bind.annotation.ResponseStatus;
13 |
14 | import javax.servlet.http.HttpServletRequest;
15 |
16 | import static org.springframework.http.HttpStatus.BAD_REQUEST;
17 |
18 | @ControllerAdvice
19 | public class EmailValidationExceptionHandler extends BaseExceptionHandler {
20 |
21 | @ExceptionHandler
22 | @ResponseStatus(BAD_REQUEST)
23 | @ResponseBody
24 | public ErrorResponse handleEmailValidationException(HttpServletRequest request, EmailValidationException e) {
25 | ErrorResponse response = new ErrorResponse(ErrorCodes.FORM_ERROR.getStatus(), translate(request, "auth.error.emailValidation", "Email is used or incorrect"));
26 | if (e.getErrors() != null) {
27 | for (ValidationErrorCode c : e.getErrors()) {
28 | response.addField(c.getField(), Nulls.notNull(c.getMessage(), c.getCode().getValue()));
29 | }
30 | }
31 | return response;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/PasswordValidationExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller.exceptionhandler;
2 |
3 | import io.rocketbase.commons.dto.ErrorResponse;
4 | import io.rocketbase.commons.dto.validation.PasswordErrorCodes;
5 | import io.rocketbase.commons.exception.ErrorCodes;
6 | import io.rocketbase.commons.exception.PasswordValidationException;
7 | import io.rocketbase.commons.exception.ValidationErrorCode;
8 | import io.rocketbase.commons.util.Nulls;
9 | import org.springframework.web.bind.annotation.ControllerAdvice;
10 | import org.springframework.web.bind.annotation.ExceptionHandler;
11 | import org.springframework.web.bind.annotation.ResponseBody;
12 | import org.springframework.web.bind.annotation.ResponseStatus;
13 |
14 | import javax.servlet.http.HttpServletRequest;
15 |
16 | import static org.springframework.http.HttpStatus.BAD_REQUEST;
17 |
18 | @ControllerAdvice
19 | public class PasswordValidationExceptionHandler extends BaseExceptionHandler {
20 |
21 | @ExceptionHandler
22 | @ResponseStatus(BAD_REQUEST)
23 | @ResponseBody
24 | public ErrorResponse handlePasswordValidationException(HttpServletRequest request, PasswordValidationException e) {
25 | ErrorResponse response = new ErrorResponse(ErrorCodes.FORM_ERROR.getStatus(), translate(request, "auth.error.passwordValidation", "Password not fitting requirements"));
26 | if (e.getErrors() != null) {
27 | for (ValidationErrorCode c : e.getErrors()) {
28 | response.addField(c.getField(), Nulls.notNull(c.getMessage(), c.getCode().getValue()));
29 | }
30 | }
31 | return response;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/RegistrationExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller.exceptionhandler;
2 |
3 | import io.rocketbase.commons.dto.ErrorResponse;
4 | import io.rocketbase.commons.exception.AuthErrorCodes;
5 | import io.rocketbase.commons.exception.RegistrationException;
6 | import io.rocketbase.commons.exception.ValidationErrorCode;
7 | import io.rocketbase.commons.util.Nulls;
8 | import org.springframework.web.bind.annotation.ControllerAdvice;
9 | import org.springframework.web.bind.annotation.ExceptionHandler;
10 | import org.springframework.web.bind.annotation.ResponseBody;
11 | import org.springframework.web.bind.annotation.ResponseStatus;
12 |
13 | import javax.servlet.http.HttpServletRequest;
14 | import java.util.Set;
15 |
16 | import static org.springframework.http.HttpStatus.BAD_REQUEST;
17 |
18 | @ControllerAdvice
19 | public class RegistrationExceptionHandler extends BaseExceptionHandler {
20 |
21 | @ExceptionHandler
22 | @ResponseStatus(BAD_REQUEST)
23 | @ResponseBody
24 | public ErrorResponse handleRegistrationException(HttpServletRequest request, RegistrationException e) {
25 | ErrorResponse response = new ErrorResponse(AuthErrorCodes.REGISTRATION.getStatus(), translate(request, "auth.error.registration", "Registation failed"));
26 | addErrors(e.getUsernameErrors(), "username", response);
27 | addErrors(e.getPasswordErrors(), "password", response);
28 | addErrors(e.getEmailErrors(), "email", response);
29 | return response;
30 | }
31 |
32 | public > void addErrors(Set> errors, String path, ErrorResponse response) {
33 | if (errors != null && !errors.isEmpty()) {
34 | for (ValidationErrorCode v : errors) {
35 | response.addField(path, Nulls.notNull(v.getMessage(), v.getCode().name()));
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/UnknownUserExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller.exceptionhandler;
2 |
3 | import io.rocketbase.commons.dto.ErrorResponse;
4 | import io.rocketbase.commons.exception.AuthErrorCodes;
5 | import io.rocketbase.commons.exception.UnknownUserException;
6 | import org.springframework.web.bind.annotation.ControllerAdvice;
7 | import org.springframework.web.bind.annotation.ExceptionHandler;
8 | import org.springframework.web.bind.annotation.ResponseBody;
9 | import org.springframework.web.bind.annotation.ResponseStatus;
10 |
11 | import javax.servlet.http.HttpServletRequest;
12 |
13 | import static org.springframework.http.HttpStatus.BAD_REQUEST;
14 |
15 | @ControllerAdvice
16 | public class UnknownUserExceptionHandler extends BaseExceptionHandler {
17 |
18 | @ExceptionHandler
19 | @ResponseStatus(BAD_REQUEST)
20 | @ResponseBody
21 | public ErrorResponse handleUnknownUserException(HttpServletRequest request, UnknownUserException e) {
22 | ErrorResponse errorResponse = new ErrorResponse(AuthErrorCodes.UNKNOWN_USER.getStatus(), translate(request, "auth.error.unknownUser", "User is unknown"));
23 | if (e.isEmail()) {
24 | errorResponse.addField("email", translate(request, "auth.error.unknownEmail", "Email is unknown"));
25 | }
26 | if (e.isUsername()) {
27 | errorResponse.addField("username", translate(request, "auth.error.unknownUser", "User is unknown"));
28 | }
29 | return errorResponse;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/UsernameValidationExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller.exceptionhandler;
2 |
3 | import io.rocketbase.commons.dto.ErrorResponse;
4 | import io.rocketbase.commons.dto.validation.UsernameErrorCodes;
5 | import io.rocketbase.commons.exception.ErrorCodes;
6 | import io.rocketbase.commons.exception.UsernameValidationException;
7 | import io.rocketbase.commons.exception.ValidationErrorCode;
8 | import io.rocketbase.commons.util.Nulls;
9 | import org.springframework.web.bind.annotation.ControllerAdvice;
10 | import org.springframework.web.bind.annotation.ExceptionHandler;
11 | import org.springframework.web.bind.annotation.ResponseBody;
12 | import org.springframework.web.bind.annotation.ResponseStatus;
13 |
14 | import javax.servlet.http.HttpServletRequest;
15 | import java.util.HashMap;
16 |
17 | import static org.springframework.http.HttpStatus.BAD_REQUEST;
18 |
19 | @ControllerAdvice
20 | public class UsernameValidationExceptionHandler extends BaseExceptionHandler {
21 |
22 | @ExceptionHandler
23 | @ResponseStatus(BAD_REQUEST)
24 | @ResponseBody
25 | public ErrorResponse handleUsernameValidationException(HttpServletRequest request, UsernameValidationException e) {
26 | ErrorResponse response = new ErrorResponse(ErrorCodes.FORM_ERROR.getStatus(), translate(request, "auth.error.usernameValidation", "Username not fitting requirements"));
27 | response.setFields(new HashMap<>());
28 | if (e.getErrors() != null) {
29 | for (ValidationErrorCode c : e.getErrors()) {
30 | response.addField(c.getField(), Nulls.notNull(c.getMessage(), c.getCode().getValue()));
31 | }
32 | }
33 | return response;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/commons-auth-server/src/main/java/io/rocketbase/commons/controller/exceptionhandler/VerificationExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller.exceptionhandler;
2 |
3 | import io.rocketbase.commons.dto.ErrorResponse;
4 | import io.rocketbase.commons.exception.AuthErrorCodes;
5 | import io.rocketbase.commons.exception.VerificationException;
6 | import org.springframework.web.bind.annotation.ControllerAdvice;
7 | import org.springframework.web.bind.annotation.ExceptionHandler;
8 | import org.springframework.web.bind.annotation.ResponseBody;
9 | import org.springframework.web.bind.annotation.ResponseStatus;
10 |
11 | import javax.servlet.http.HttpServletRequest;
12 |
13 | import static org.springframework.http.HttpStatus.BAD_REQUEST;
14 |
15 | @ControllerAdvice
16 | public class VerificationExceptionHandler extends BaseExceptionHandler {
17 |
18 | @ExceptionHandler
19 | @ResponseStatus(BAD_REQUEST)
20 | @ResponseBody
21 | public ErrorResponse handleVerificationException(HttpServletRequest request, VerificationException e) {
22 | return new ErrorResponse(AuthErrorCodes.VERIFICATION_INVALID.getStatus(), translate(request, "auth.error.verification", "Verification is invalid or expired"))
23 | .addField(e.getField(), translate(request, "auth.error.verification", "Verification is invalid or expired"));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/commons-auth-server/src/main/resources/META-INF/resources/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rocketbase-io/commons-auth/c86f5c1caba8c63f9f91fd4828395162f35f23bc/commons-auth-server/src/main/resources/META-INF/resources/favicon.ico
--------------------------------------------------------------------------------
/commons-auth-server/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | io.rocketbase.commons.config.AuthServerAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-server/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
--------------------------------------------------------------------------------
1 | io.rocketbase.commons.config.AuthServerAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-server/src/test/java/io/rocketbase/commons/BaseIntegrationTestPrefixed.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons;
2 |
3 | import io.rocketbase.commons.test.BaseIntegrationTest;
4 |
5 | public class BaseIntegrationTestPrefixed extends BaseIntegrationTest {
6 |
7 | @Override
8 | public String getBaseUrl() {
9 | // added prefix for testing... see: application-test.yml -> auth.prefix
10 | return super.getBaseUrl() + "/test";
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/commons-auth-server/src/test/java/io/rocketbase/commons/TestApplication.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons;
2 |
3 | import io.rocketbase.commons.service.email.EmailSender;
4 | import io.rocketbase.commons.test.EmailSenderTest;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.context.annotation.Bean;
8 |
9 | @SpringBootApplication
10 | public class TestApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(TestApplication.class, args);
14 | }
15 |
16 | @Bean
17 | public EmailSender emailSender() {
18 | return new EmailSenderTest();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/commons-auth-server/src/test/java/io/rocketbase/commons/controller/ImpersonateControllerTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.controller;
2 |
3 | import io.rocketbase.commons.BaseIntegrationTestPrefixed;
4 | import io.rocketbase.commons.adapters.JwtRestTemplate;
5 | import io.rocketbase.commons.adapters.JwtTokenProvider;
6 | import io.rocketbase.commons.adapters.SimpleJwtTokenProvider;
7 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
8 | import io.rocketbase.commons.model.AppUserEntity;
9 | import io.rocketbase.commons.resource.ImpersonateResource;
10 | import io.rocketbase.commons.test.ModifiedJwtTokenService;
11 | import io.rocketbase.commons.util.JwtTokenBody;
12 | import io.rocketbase.commons.util.JwtTokenDecoder;
13 | import org.junit.Test;
14 |
15 | import javax.annotation.Resource;
16 |
17 | import static org.hamcrest.MatcherAssert.assertThat;
18 | import static org.hamcrest.Matchers.*;
19 |
20 | public class ImpersonateControllerTest extends BaseIntegrationTestPrefixed {
21 |
22 | @Resource
23 | private ModifiedJwtTokenService modifiedJwtTokenService;
24 |
25 | @Test
26 | public void impersonate() {
27 | // given
28 | AppUserEntity admin = getAppUser("admin");
29 | JwtTokenProvider tokenProvider = new SimpleJwtTokenProvider(getBaseUrl(), modifiedJwtTokenService.generateTokenBundle(admin));
30 | AppUserEntity user = getAppUser("user");
31 |
32 |
33 | // when
34 | ImpersonateResource impersonateResource = new ImpersonateResource(new JwtRestTemplate(tokenProvider));
35 | JwtTokenBundle response = impersonateResource.impersonate(user.getId());
36 |
37 | // then
38 | assertThat(response, notNullValue());
39 | JwtTokenBody jwtTokenBody = JwtTokenDecoder.decodeTokenBody(response.getToken());
40 | assertThat(jwtTokenBody.getUsername(), equalTo(user.getUsername()));
41 | assertThat(jwtTokenBody.getScopes(), containsInAnyOrder("ROLE_" + user.getRoles().get(0)));
42 | }
43 | }
--------------------------------------------------------------------------------
/commons-auth-server/src/test/resources/application-test.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | # json configuration
3 | jackson:
4 | serialization:
5 | WRITE_DATES_AS_TIMESTAMPS: false
6 | INDENT_OUTPUT: true
7 | default-property-inclusion: NON_NULL
8 | # email
9 | mail:
10 | host: localhost
11 | username: username
12 | password: secret
13 | port: 2525
14 | properties:
15 | mail:
16 | debug: false
17 | smtp:
18 | debug: false
19 | auth: true
20 | starttls: true
21 | test-connection: false
22 |
23 | main:
24 | allow-circular-references: true
25 |
26 | logging:
27 | level:
28 | io.rocketbase: TRACE
29 |
30 | # auth configuration
31 | auth:
32 | jwt:
33 | secret: 'P0UoSCtNYlBlU2hWbVlxM3Q2dzl6JEMmRilKQE5jUmZUalduWnI0dTd4IUElRCpHLUthUGRTZ1ZrWHAyczV2OA=='
34 | user-cache-time: 0
35 | prefix: /test
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/AppInviteApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.converter.AppInviteConverter;
4 | import io.rocketbase.commons.dto.PageableResult;
5 | import io.rocketbase.commons.dto.appinvite.AppInviteRead;
6 | import io.rocketbase.commons.dto.appinvite.InviteRequest;
7 | import io.rocketbase.commons.dto.appinvite.QueryAppInvite;
8 | import io.rocketbase.commons.model.AppInviteEntity;
9 | import io.rocketbase.commons.service.invite.AppInviteService;
10 | import lombok.RequiredArgsConstructor;
11 | import org.springframework.data.domain.Page;
12 | import org.springframework.data.domain.Pageable;
13 |
14 | @RequiredArgsConstructor
15 | public class AppInviteApiService implements AppInviteApi, BaseApiService {
16 |
17 | private final AppInviteService appInviteService;
18 | private final AppInviteConverter converter;
19 |
20 | @Override
21 | public PageableResult find(QueryAppInvite query, Pageable pageable) {
22 | Page page = appInviteService.findAll(query, pageable);
23 | return PageableResult.contentPage(converter.fromEntities(page.getContent()), page);
24 | }
25 |
26 | @Override
27 | public AppInviteRead invite(InviteRequest inviteRequest) {
28 | return converter.fromEntity(appInviteService.createInvite(inviteRequest, getBaseUrl()));
29 | }
30 |
31 | @Override
32 | public void delete(String id) {
33 | appInviteService.deleteInvite(id);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/BaseApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.util.Nulls;
4 | import org.springframework.web.context.request.RequestContextHolder;
5 | import org.springframework.web.context.request.ServletRequestAttributes;
6 | import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
7 |
8 | import javax.servlet.http.HttpServletRequest;
9 |
10 | public interface BaseApiService {
11 |
12 | default String getBaseUrl() {
13 | try {
14 | ServletUriComponentsBuilder uriComponentsBuilder = ServletUriComponentsBuilder.fromCurrentContextPath();
15 | // in some cases uriComponentsBuilder will ignore ssl (checks for X-Forwarded-Ssl: on) ignore this behaviour...
16 | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
17 | String scheme = Nulls.notNull(request.getHeader("x-forwarded-proto"), request.getHeader("x-scheme"));
18 | if ("https".equalsIgnoreCase(scheme)) {
19 | uriComponentsBuilder.scheme(scheme);
20 | }
21 | return uriComponentsBuilder.toUriString();
22 | } catch (Exception e) {
23 | }
24 | return null;
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/ForgotPasswordApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.dto.ExpirationInfo;
4 | import io.rocketbase.commons.dto.forgot.ForgotPasswordRequest;
5 | import io.rocketbase.commons.dto.forgot.PerformPasswordResetRequest;
6 | import io.rocketbase.commons.service.forgot.AppUserForgotPasswordService;
7 | import lombok.RequiredArgsConstructor;
8 |
9 | @RequiredArgsConstructor
10 | public class ForgotPasswordApiService implements ForgotPasswordApi, BaseApiService {
11 |
12 | private final AppUserForgotPasswordService forgotPasswordService;
13 |
14 | @Override
15 | public ExpirationInfo forgotPassword(ForgotPasswordRequest forgotPassword) {
16 | return forgotPasswordService.requestPasswordReset(forgotPassword, getBaseUrl());
17 | }
18 |
19 | @Override
20 | public void resetPassword(PerformPasswordResetRequest performPasswordReset) {
21 | forgotPasswordService.resetPassword(performPasswordReset);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/ImpersonateApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
4 | import io.rocketbase.commons.exception.NotFoundException;
5 | import io.rocketbase.commons.model.AppUserEntity;
6 | import io.rocketbase.commons.security.CommonsPrincipal;
7 | import io.rocketbase.commons.service.impersonate.ImpersonateService;
8 | import io.rocketbase.commons.service.user.AppUserService;
9 | import lombok.RequiredArgsConstructor;
10 |
11 | @RequiredArgsConstructor
12 | public class ImpersonateApiService implements ImpersonateApi {
13 |
14 | private final ImpersonateService impersonateService;
15 | private final AppUserService appUserService;
16 |
17 | @Override
18 | public JwtTokenBundle impersonate(String userIdOrUsername) {
19 | AppUserEntity entity = appUserService.findByIdOrUsername(userIdOrUsername).orElseThrow(NotFoundException::new);
20 | return impersonateService.getImpersonateBundle(CommonsPrincipal.getCurrent(), entity);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/InviteApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.converter.AppInviteConverter;
4 | import io.rocketbase.commons.converter.AppUserConverter;
5 | import io.rocketbase.commons.dto.appinvite.AppInviteRead;
6 | import io.rocketbase.commons.dto.appinvite.ConfirmInviteRequest;
7 | import io.rocketbase.commons.dto.appuser.AppUserRead;
8 | import io.rocketbase.commons.model.AppUserEntity;
9 | import io.rocketbase.commons.service.invite.AppInviteService;
10 | import lombok.RequiredArgsConstructor;
11 |
12 | @RequiredArgsConstructor
13 | public class InviteApiService implements InviteApi {
14 |
15 | private final AppInviteService appInviteService;
16 | private final AppInviteConverter inviteConverter;
17 | private final AppUserConverter userConverter;
18 |
19 | @Override
20 | public AppInviteRead verify(String inviteId) {
21 | return inviteConverter.fromEntity(appInviteService.verifyInvite(inviteId));
22 | }
23 |
24 | @Override
25 | public AppUserRead transformToUser(ConfirmInviteRequest confirmInvite) {
26 | AppUserEntity userEntity = appInviteService.confirmInvite(confirmInvite);
27 | return userConverter.fromEntity(userEntity);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/LoginApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.dto.authentication.LoginRequest;
4 | import io.rocketbase.commons.dto.authentication.LoginResponse;
5 | import io.rocketbase.commons.model.AppUserToken;
6 | import io.rocketbase.commons.security.JwtTokenService;
7 | import io.rocketbase.commons.service.auth.LoginService;
8 | import io.rocketbase.commons.service.user.AppUserService;
9 | import lombok.RequiredArgsConstructor;
10 |
11 | @RequiredArgsConstructor
12 | public class LoginApiService implements LoginApi {
13 |
14 | private final LoginService loginService;
15 |
16 | private final JwtTokenService jwtTokenService;
17 |
18 | private final AppUserService appUserService;
19 |
20 | @Override
21 | public LoginResponse login(LoginRequest login) {
22 | return loginService.performLogin(login.getUsername(), login.getPassword());
23 | }
24 |
25 | @Override
26 | public String getNewAccessToken(String refreshToken) {
27 | AppUserToken appUserToken = jwtTokenService.parseToken(refreshToken);
28 | if (!appUserToken.hasRole(JwtTokenService.REFRESH_TOKEN)) {
29 | throw new RuntimeException("need a valid refresh-token!");
30 | }
31 | return jwtTokenService.generateAccessToken(appUserService.getByUsername(appUserToken.getUsername()));
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/RegistrationApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.converter.AppUserConverter;
4 | import io.rocketbase.commons.dto.ExpirationInfo;
5 | import io.rocketbase.commons.dto.appuser.AppUserRead;
6 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
7 | import io.rocketbase.commons.dto.registration.RegistrationRequest;
8 | import io.rocketbase.commons.model.AppUserEntity;
9 | import io.rocketbase.commons.security.JwtTokenService;
10 | import io.rocketbase.commons.service.registration.RegistrationService;
11 | import lombok.RequiredArgsConstructor;
12 |
13 | @RequiredArgsConstructor
14 | public class RegistrationApiService implements RegistrationApi, BaseApiService {
15 |
16 | private final RegistrationService registrationService;
17 | private final AppUserConverter converter;
18 | private final JwtTokenService jwtTokenService;
19 |
20 | @Override
21 | public ExpirationInfo register(RegistrationRequest registration) {
22 | ExpirationInfo expirationInfo = registrationService.register(registration, getBaseUrl());
23 | return ExpirationInfo.builder()
24 | .expires(expirationInfo.getExpires())
25 | .detail(converter.fromEntity(expirationInfo.getDetail()))
26 | .build();
27 | }
28 |
29 | @Override
30 | public JwtTokenBundle verify(String verification) {
31 | AppUserEntity appUserEntity = registrationService.verifyRegistration(verification);
32 | return jwtTokenService.generateTokenBundle(appUserEntity);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/UserSearchApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.dto.PageableResult;
4 | import io.rocketbase.commons.dto.appuser.QueryAppUser;
5 | import io.rocketbase.commons.model.AppUserEntity;
6 | import io.rocketbase.commons.model.AppUserReference;
7 | import io.rocketbase.commons.service.user.AppUserService;
8 | import lombok.RequiredArgsConstructor;
9 | import org.springframework.data.domain.Page;
10 | import org.springframework.data.domain.Pageable;
11 |
12 | import java.util.Optional;
13 | import java.util.stream.Collectors;
14 |
15 | @RequiredArgsConstructor
16 | public class UserSearchApiService implements UserSearchApi {
17 |
18 | private final AppUserService appUserService;
19 |
20 | @Override
21 | public PageableResult search(QueryAppUser query, Pageable pageable) {
22 | Page page = appUserService.findAll(query, pageable);
23 | return PageableResult.contentPage(page.stream().map(AppUserEntity::toReference).collect(Collectors.toList()), page);
24 | }
25 |
26 | @Override
27 | public Optional findByUsernameOrId(String usernameOrId) {
28 | Optional optional = appUserService.findByIdOrUsername(usernameOrId);
29 | return optional.isPresent() ? Optional.of(optional.get().toReference()) : Optional.empty();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/api/ValidationApiService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.api;
2 |
3 | import io.rocketbase.commons.converter.ValidationConverter;
4 | import io.rocketbase.commons.dto.validation.*;
5 | import io.rocketbase.commons.exception.ValidationErrorCode;
6 | import io.rocketbase.commons.service.validation.ValidationService;
7 | import lombok.RequiredArgsConstructor;
8 |
9 | import java.util.Set;
10 |
11 | @RequiredArgsConstructor
12 | public class ValidationApiService implements ValidationApi {
13 |
14 | private final ValidationService validationService;
15 |
16 | @Override
17 | public ValidationResponse validatePassword(String password) {
18 | Set> details = validationService.getPasswordValidationDetails(null, password);
19 | return ValidationConverter.convert(details);
20 | }
21 |
22 | @Override
23 | public ValidationResponse validateUsername(String username) {
24 | Set> details = validationService.getUsernameValidationDetails(null, username);
25 | return ValidationConverter.convert(details);
26 | }
27 |
28 | @Override
29 | public ValidationResponse validateEmail(String email) {
30 | Set> details = validationService.getEmailValidationDetails(null, email);
31 | return ValidationConverter.convert(details);
32 | }
33 |
34 | @Override
35 | public ValidationResponse validateToken(String token) {
36 | Set> details = validationService.getTokenValidationDetails(token);
37 | return ValidationConverter.convert(details);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/service/auth/LoginService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.auth;
2 |
3 | import io.rocketbase.commons.dto.authentication.LoginResponse;
4 |
5 | public interface LoginService {
6 |
7 | LoginResponse performLogin(String username, String password);
8 | }
9 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/service/change/ChangeAppUserWithConfirmService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.change;
2 |
3 | import io.rocketbase.commons.dto.ExpirationInfo;
4 | import io.rocketbase.commons.dto.authentication.EmailChangeRequest;
5 | import io.rocketbase.commons.exception.EmailValidationException;
6 | import io.rocketbase.commons.exception.VerificationException;
7 | import io.rocketbase.commons.model.AppUserEntity;
8 | import io.rocketbase.commons.service.FeedbackActionService;
9 |
10 | public interface ChangeAppUserWithConfirmService extends FeedbackActionService {
11 |
12 | ExpirationInfo handleEmailChangeRequest(String userId, EmailChangeRequest changeRequest, String baseUrl) throws EmailValidationException;
13 |
14 | AppUserEntity confirmEmailChange(String verification) throws VerificationException;
15 | }
16 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/service/email/MailContentConfig.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.email;
2 |
3 | import io.rocketbase.commons.model.AppInviteEntity;
4 | import io.rocketbase.commons.model.AppUserReference;
5 | import io.rocketbase.mail.model.HtmlTextEmail;
6 |
7 | public interface MailContentConfig {
8 |
9 | HtmlTextEmail register(AppUserReference user, String actionUrl);
10 |
11 | String registerSubject(AppUserReference user);
12 |
13 | HtmlTextEmail forgotPassword(AppUserReference user, String actionUrl);
14 |
15 | String forgotPasswordSubject(AppUserReference user);
16 |
17 | HtmlTextEmail invite(AppInviteEntity invite, String actionUrl);
18 |
19 | String inviteSubject(AppInviteEntity invite);
20 |
21 | HtmlTextEmail changeEmail(AppUserReference user, String newEmailAddress, String actionUrl);
22 |
23 | String changeEmailSubject(AppUserReference user);
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/service/forgot/AppUserForgotPasswordService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.forgot;
2 |
3 | import io.rocketbase.commons.dto.ExpirationInfo;
4 | import io.rocketbase.commons.dto.forgot.ForgotPasswordRequest;
5 | import io.rocketbase.commons.dto.forgot.PerformPasswordResetRequest;
6 | import io.rocketbase.commons.model.AppUserEntity;
7 | import io.rocketbase.commons.service.FeedbackActionService;
8 |
9 | public interface AppUserForgotPasswordService extends FeedbackActionService {
10 |
11 | ExpirationInfo requestPasswordReset(ForgotPasswordRequest forgotPassword, String baseUrl);
12 |
13 | AppUserEntity resetPassword(PerformPasswordResetRequest performPasswordReset);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/service/impersonate/DefaultImpersonateService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.impersonate;
2 |
3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
4 | import io.rocketbase.commons.event.ImpersonateEvent;
5 | import io.rocketbase.commons.model.AppUserToken;
6 | import io.rocketbase.commons.security.JwtTokenService;
7 | import org.springframework.context.ApplicationEventPublisher;
8 |
9 | import javax.annotation.Resource;
10 |
11 | public class DefaultImpersonateService implements ImpersonateService {
12 |
13 | @Resource
14 | private JwtTokenService jwtTokenService;
15 |
16 | @Resource
17 | private ApplicationEventPublisher applicationEventPublisher;
18 |
19 | @Override
20 | public JwtTokenBundle getImpersonateBundle(AppUserToken requestedBy, AppUserToken impersonateAs) {
21 | applicationEventPublisher.publishEvent(new ImpersonateEvent(this, requestedBy, impersonateAs));
22 |
23 | return jwtTokenService.generateTokenBundle(impersonateAs);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/service/impersonate/ImpersonateService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.impersonate;
2 |
3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
4 | import io.rocketbase.commons.model.AppUserToken;
5 |
6 | public interface ImpersonateService {
7 |
8 | JwtTokenBundle getImpersonateBundle(AppUserToken requestedBy, AppUserToken impersonateAs);
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/service/invite/AppInviteService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.invite;
2 |
3 | import io.rocketbase.commons.dto.appinvite.ConfirmInviteRequest;
4 | import io.rocketbase.commons.dto.appinvite.InviteRequest;
5 | import io.rocketbase.commons.dto.appinvite.QueryAppInvite;
6 | import io.rocketbase.commons.exception.BadRequestException;
7 | import io.rocketbase.commons.exception.NotFoundException;
8 | import io.rocketbase.commons.exception.RegistrationException;
9 | import io.rocketbase.commons.exception.VerificationException;
10 | import io.rocketbase.commons.model.AppInviteEntity;
11 | import io.rocketbase.commons.model.AppUserEntity;
12 | import io.rocketbase.commons.service.FeedbackActionService;
13 | import org.springframework.data.domain.Page;
14 | import org.springframework.data.domain.Pageable;
15 |
16 | public interface AppInviteService extends FeedbackActionService {
17 |
18 | /**
19 | * creates an invite and sent him a invite email. during confirm process invitor will fill required fields like username, password to a new user.
20 | * time for verification could be configure AuthProperties.inviteExpiration
21 | *
22 | * @throws BadRequestException
23 | */
24 | AppInviteEntity createInvite(InviteRequest request, String baseUrl) throws BadRequestException;
25 |
26 | AppInviteEntity verifyInvite(String inviteId) throws VerificationException, NotFoundException;
27 |
28 | /**
29 | * checks verification-token, set password and possible update firstName, lastName
30 | *
31 | * @throws RegistrationException
32 | * @throws VerificationException
33 | */
34 | AppUserEntity confirmInvite(ConfirmInviteRequest request) throws RegistrationException, VerificationException;
35 |
36 | /**
37 | * delegates query to persistence service
38 | * so that for all main function {@link AppInviteService} is the main service - by dealing with invites
39 | */
40 | Page findAll(QueryAppInvite query, Pageable pageable);
41 |
42 | void deleteInvite(String inviteId);
43 | }
44 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/service/registration/RegistrationService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.registration;
2 |
3 | import io.rocketbase.commons.dto.ExpirationInfo;
4 | import io.rocketbase.commons.dto.registration.RegistrationRequest;
5 | import io.rocketbase.commons.exception.RegistrationException;
6 | import io.rocketbase.commons.exception.VerificationException;
7 | import io.rocketbase.commons.model.AppUserEntity;
8 | import io.rocketbase.commons.service.FeedbackActionService;
9 |
10 | public interface RegistrationService extends FeedbackActionService {
11 |
12 | ExpirationInfo register(RegistrationRequest registration, String baseUrl) throws RegistrationException;
13 |
14 | AppUserEntity verifyRegistration(String verification) throws VerificationException;
15 | }
16 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/java/io/rocketbase/commons/util/JwtTokenStoreService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.util;
2 |
3 | import io.rocketbase.commons.dto.authentication.JwtTokenBundle;
4 | import io.rocketbase.commons.exception.TokenRefreshException;
5 | import io.rocketbase.commons.model.AppUserToken;
6 | import io.rocketbase.commons.security.JwtTokenService;
7 | import lombok.extern.slf4j.Slf4j;
8 |
9 | @Slf4j
10 | public class JwtTokenStoreService extends AbstractJwtTokenStore {
11 |
12 | private final JwtTokenService jwtTokenService;
13 |
14 | public JwtTokenStoreService(JwtTokenBundle tokenBundle, JwtTokenService jwtTokenService) {
15 | super(tokenBundle);
16 | this.jwtTokenService = jwtTokenService;
17 | }
18 |
19 | @Override
20 | public void refreshToken() throws TokenRefreshException {
21 | try {
22 | AppUserToken token = jwtTokenService.parseToken(getTokenBundle().getRefreshToken());
23 | tokenBundle.setToken(jwtTokenService.generateAccessToken(token));
24 |
25 | lastToken = null;
26 | exp = null;
27 |
28 | if (log.isTraceEnabled()) {
29 | log.trace("refreshed token before processing http-request");
30 | }
31 | } catch (Exception e) {
32 | if (log.isDebugEnabled()) {
33 | log.debug("couldn't refresh token. got error: {}", e.getMessage());
34 | }
35 | throw new TokenRefreshException();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/commons-auth-service/src/main/resources/META-INF/spring.factories:
--------------------------------------------------------------------------------
1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2 | io.rocketbase.commons.config.AuthServiceAutoConfiguration,\
3 | io.rocketbase.commons.config.AuthApiAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-service/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:
--------------------------------------------------------------------------------
1 | io.rocketbase.commons.config.AuthServiceAutoConfiguration
2 | io.rocketbase.commons.config.AuthApiAutoConfiguration
--------------------------------------------------------------------------------
/commons-auth-service/src/test/java/io/rocketbase/commons/Application.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons;
2 |
3 | import io.rocketbase.commons.service.email.EmailSender;
4 | import io.rocketbase.commons.test.EmailSenderTest;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.context.annotation.Bean;
8 |
9 | @SpringBootApplication
10 | public class Application {
11 |
12 | @Bean
13 | public EmailSender emailSender() {
14 | return new EmailSenderTest();
15 | }
16 |
17 | public static void main(String[] args) throws Exception {
18 | SpringApplication.run(Application.class, args);
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/commons-auth-service/src/test/java/io/rocketbase/commons/service/email/EmailServiceTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.service.email;
2 |
3 | import io.rocketbase.commons.config.EmailProperties;
4 | import io.rocketbase.commons.model.AppUserEntity;
5 | import io.rocketbase.commons.test.BaseIntegrationTest;
6 | import io.rocketbase.commons.test.EmailSenderTest;
7 | import org.junit.Test;
8 | import org.springframework.context.i18n.LocaleContextHolder;
9 |
10 | import javax.annotation.Resource;
11 | import java.util.Locale;
12 |
13 | import static org.hamcrest.MatcherAssert.assertThat;
14 | import static org.hamcrest.Matchers.*;
15 |
16 | public class EmailServiceTest extends BaseIntegrationTest {
17 |
18 | @Resource
19 | private AuthEmailService emailService;
20 |
21 | @Resource
22 | private EmailSenderTest emailSenderTest;
23 |
24 | @Test
25 | public void simpleSendRegistrationEmail() throws Exception {
26 | // given
27 | AppUserEntity user = getAppUser();
28 |
29 | EmailProperties emailProperties = new EmailProperties();
30 |
31 | // when
32 | emailService.sentRegistrationEmail(user, "http://localhost:8080/?verification=token");
33 |
34 | // then
35 |
36 | assertThat(emailSenderTest.getSubject(), startsWith(emailProperties.getSubjectPrefix() + " "));
37 | assertThat(emailSenderTest.getTo().getEmail(), containsString(user.getEmail()));
38 | assertThat(emailSenderTest.getHtml().length(), greaterThan(0));
39 | }
40 |
41 | @Test
42 | public void germanRegistrationEmail() throws Exception {
43 | // given
44 | AppUserEntity user = getAppUser();
45 |
46 | EmailProperties emailProperties = new EmailProperties();
47 | LocaleContextHolder.setLocale(Locale.GERMAN);
48 |
49 | // when
50 | emailService.sentRegistrationEmail(user, "http://localhost:8080/?verification=token");
51 |
52 | // then
53 |
54 | assertThat(emailSenderTest.getSubject(), is(String.format("%s Registrierung bestätigen", emailProperties.getSubjectPrefix())));
55 | assertThat(emailSenderTest.getText(), containsString("Sie Ihre Registrierung durch einen Klick auf den"));
56 | }
57 |
58 |
59 |
60 | }
--------------------------------------------------------------------------------
/commons-auth-service/src/test/resources/application-test.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | # json configuration
3 | jackson:
4 | serialization:
5 | WRITE_DATES_AS_TIMESTAMPS: false
6 | INDENT_OUTPUT: true
7 | default-property-inclusion: NON_NULL
8 | # email
9 | mail:
10 | host: localhost
11 | username: username
12 | password: secret
13 | port: 2525
14 | properties:
15 | mail:
16 | debug: false
17 | smtp:
18 | debug: false
19 | auth: true
20 | starttls: true
21 | test-connection: false
22 |
23 | main:
24 | allow-circular-references: true
25 |
26 | logging:
27 | level:
28 | io.rocketbase: TRACE
29 |
30 | # auth configuration
31 | auth:
32 | jwt:
33 | secret: 'P0UoSCtNYlBlU2hWbVlxM3Q2dzl6JEMmRilKQE5jUmZUalduWnI0dTd4IUElRCpHLUthUGRTZ1ZrWHAyczV2OA=='
34 | user-cache-time: 0
35 | prefix: /test
--------------------------------------------------------------------------------
/commons-auth-test/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | commons-auth
7 | io.rocketbase.commons
8 | LATEST-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | commons-auth-test
13 |
14 |
15 |
16 | io.rocketbase.commons
17 | commons-auth-core
18 | ${project.version}
19 |
20 |
21 | javax.annotation
22 | javax.annotation-api
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-test
27 |
28 |
29 | junit
30 | junit
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/commons-auth-test/src/main/java/io/rocketbase/commons/test/BaseIntegrationTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.test;
2 |
3 |
4 | import io.rocketbase.commons.model.AppUserEntity;
5 | import io.rocketbase.commons.security.JwtTokenService;
6 | import io.rocketbase.commons.test.adapters.AuthRestTestTemplate;
7 | import lombok.Getter;
8 | import org.junit.Before;
9 | import org.junit.runner.RunWith;
10 | import org.springframework.beans.factory.annotation.Value;
11 | import org.springframework.boot.test.context.SpringBootTest;
12 | import org.springframework.test.context.ActiveProfiles;
13 | import org.springframework.test.context.junit4.SpringRunner;
14 |
15 | import javax.annotation.Resource;
16 |
17 | @RunWith(SpringRunner.class)
18 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
19 | @ActiveProfiles(profiles = "test")
20 | public abstract class BaseIntegrationTest {
21 |
22 | @Getter
23 | @Value("http://localhost:${local.server.port}")
24 | protected String baseUrl;
25 |
26 | @Resource
27 | private AppUserPersistenceTestService appUserPersistenceTestService;
28 |
29 | @Resource
30 | private JwtTokenService jwtTokenService;
31 |
32 | protected AppUserEntity getAppUser() {
33 | return getAppUser("user");
34 | }
35 |
36 | protected AppUserEntity getAppAdminUser() {
37 | return getAppUser("admin");
38 | }
39 |
40 | protected AppUserEntity getAppUser(String username) {
41 | return appUserPersistenceTestService.findByUsername(username).get();
42 | }
43 |
44 | protected AuthRestTestTemplate getAuthRestTemplate() {
45 | return getAuthRestTemplate("user");
46 | }
47 |
48 | protected AuthRestTestTemplate getAuthRestAdminTemplate() {
49 | return getAuthRestTemplate("admin");
50 | }
51 |
52 | protected AuthRestTestTemplate getAuthRestTemplate(String username) {
53 | return new AuthRestTestTemplate(getAppUser(username), jwtTokenService);
54 | }
55 |
56 | @Before
57 | public void beforeEachTest() {
58 | appUserPersistenceTestService.resetData();
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/commons-auth-test/src/main/java/io/rocketbase/commons/test/EmailSenderTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.test;
2 |
3 | import io.rocketbase.commons.service.email.EmailAddress;
4 | import io.rocketbase.commons.service.email.EmailSender;
5 | import lombok.Getter;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | @Slf4j
9 | @Getter
10 | public class EmailSenderTest implements EmailSender {
11 |
12 | private EmailAddress to;
13 | private String subject;
14 | private String html;
15 | private String text;
16 | private EmailAddress from;
17 |
18 |
19 | @Override
20 | public void sentEmail(EmailAddress to, String subject, String html, String text, EmailAddress from) {
21 | this.to = to;
22 | this.subject = subject;
23 | this.html = html;
24 | this.text = text;
25 | this.from = from;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/commons-auth-test/src/main/java/io/rocketbase/commons/test/ModifiedJwtTokenService.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.test;
2 |
3 | import io.rocketbase.commons.config.JwtProperties;
4 | import io.rocketbase.commons.model.AppUserEntity;
5 | import io.rocketbase.commons.security.EmptyCustomAuthoritiesProvider;
6 | import io.rocketbase.commons.security.JwtTokenService;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.stereotype.Component;
10 |
11 | import java.time.Instant;
12 |
13 | @Slf4j
14 | @Component
15 | public class ModifiedJwtTokenService extends JwtTokenService {
16 |
17 | @Autowired
18 | public ModifiedJwtTokenService(JwtProperties jwtProperties) {
19 | super(jwtProperties, new EmptyCustomAuthoritiesProvider());
20 | }
21 |
22 | public String generateExpiredToken(AppUserEntity user) {
23 | return generateAccessToken(Instant.now().minusSeconds(60 * 60 * 24 * 100), user);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/commons-auth-test/src/main/java/io/rocketbase/commons/test/adapters/AuthRestTestTemplate.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.test.adapters;
2 |
3 | import io.rocketbase.commons.model.AppUserToken;
4 | import io.rocketbase.commons.resource.BasicResponseErrorHandler;
5 | import io.rocketbase.commons.security.JwtTokenService;
6 | import lombok.RequiredArgsConstructor;
7 | import org.apache.http.client.methods.HttpUriRequest;
8 | import org.springframework.http.HttpHeaders;
9 | import org.springframework.http.client.ClientHttpRequestFactory;
10 | import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
11 | import org.springframework.web.client.RestTemplate;
12 |
13 | public class AuthRestTestTemplate extends RestTemplate {
14 |
15 | public AuthRestTestTemplate(AppUserToken userToken, JwtTokenService jwtTokenService) {
16 | super(new TestClientHttpRequestFactory(userToken, jwtTokenService));
17 | setErrorHandler(new BasicResponseErrorHandler());
18 | }
19 |
20 | @RequiredArgsConstructor
21 | protected static class TestClientHttpRequestFactory extends HttpComponentsClientHttpRequestFactory implements ClientHttpRequestFactory {
22 | private final AppUserToken userToken;
23 | private final JwtTokenService jwtTokenService;
24 |
25 | @Override
26 | protected void postProcessHttpRequest(HttpUriRequest request) {
27 | request.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + jwtTokenService.generateAccessToken(userToken));
28 | }
29 | }
30 |
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/commons-auth-test/src/main/java/io/rocketbase/commons/test/model/AppInviteTestEntity.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.test.model;
2 |
3 | import com.google.common.collect.ImmutableMap;
4 | import io.rocketbase.commons.model.AppInviteEntity;
5 | import lombok.*;
6 |
7 | import java.time.Instant;
8 | import java.util.HashMap;
9 | import java.util.List;
10 | import java.util.Map;
11 | import java.util.stream.Collectors;
12 |
13 |
14 | @Data
15 | @Builder
16 | @AllArgsConstructor
17 | @NoArgsConstructor
18 | @EqualsAndHashCode(of = {"id"})
19 | public class AppInviteTestEntity implements AppInviteEntity {
20 |
21 | private String id;
22 |
23 | private String invitor;
24 |
25 | private String message;
26 |
27 | private String firstName;
28 |
29 | private String lastName;
30 |
31 | private String email;
32 |
33 | private List roles;
34 |
35 | @Builder.Default
36 | private Map keyValueMap = new HashMap<>();
37 |
38 |
39 | private Instant created;
40 |
41 | private Instant expiration;
42 |
43 | @Override
44 | public AppInviteTestEntity clone() {
45 | Map copyedKeyValueMap = getKeyValueMap() != null ? new HashMap<>(ImmutableMap.copyOf(getKeyValueMap())) : null;
46 | return AppInviteTestEntity.builder()
47 | .id(getId())
48 | .invitor(getInvitor())
49 | .message(getMessage())
50 | .email(getEmail())
51 | .roles(getRoles() != null ? getRoles().stream().map(r -> String.valueOf(r)).collect(Collectors.toList()) : null)
52 | .firstName(getFirstName())
53 | .lastName(getLastName())
54 | .created(getCreated())
55 | .expiration(getExpiration())
56 | .keyValueMap(copyedKeyValueMap)
57 | .build();
58 | }
59 |
60 | @Override
61 | public Map getKeyValues() {
62 | return keyValueMap;
63 | }
64 |
65 | @Override
66 | public void setKeyValues(Map map) {
67 | this.keyValueMap = map;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/commons-auth-test/src/test/java/io/rocketbase/commons/converter/AppUserConverterTest.java:
--------------------------------------------------------------------------------
1 | package io.rocketbase.commons.converter;
2 |
3 | import com.google.common.collect.ImmutableMap;
4 | import io.rocketbase.commons.dto.appuser.AppUserRead;
5 | import io.rocketbase.commons.model.AppUserEntity;
6 | import io.rocketbase.commons.test.model.AppUserTestEntity;
7 | import org.junit.Test;
8 |
9 | import static org.hamcrest.MatcherAssert.assertThat;
10 | import static org.hamcrest.Matchers.equalTo;
11 | import static org.hamcrest.Matchers.notNullValue;
12 |
13 | public class AppUserConverterTest {
14 |
15 | @Test
16 | public void fromEntity() {
17 | // given
18 | AppUserEntity entity = AppUserTestEntity.builder()
19 | .id("id")
20 | .email("email@test.io")
21 | .keyValueMap(ImmutableMap.builder()
22 | .put("test", "value")
23 | .put("_secret", "1234")
24 | .build())
25 | .build();
26 |
27 | // when
28 | AppUserRead appUserRead = new AppUserConverter().fromEntity(entity);
29 |
30 | // then
31 | assertThat(appUserRead, notNullValue());
32 | assertThat(appUserRead.getId(), equalTo("id"));
33 | assertThat(appUserRead.getEmail(), equalTo("email@test.io"));
34 | assertThat(appUserRead.getKeyValues().keySet().contains("test"), equalTo(true));
35 | assertThat(appUserRead.getKeyValues().keySet().contains("_secret"), equalTo(false));
36 | }
37 | }
--------------------------------------------------------------------------------
/lombok.config:
--------------------------------------------------------------------------------
1 | lombok.addLombokGeneratedAnnotation = true
--------------------------------------------------------------------------------