View Javadoc
1   /*
2    * Copyright (C) 2022 B3Partners B.V.
3    *
4    * SPDX-License-Identifier: MIT
5    */
6   package org.tailormap.api.security;
7   
8   import java.io.Serial;
9   import java.io.Serializable;
10  import java.time.ZoneId;
11  import java.time.ZonedDateTime;
12  import java.util.ArrayList;
13  import java.util.Collection;
14  import java.util.HashSet;
15  import java.util.List;
16  import java.util.Objects;
17  import org.apache.commons.lang3.StringUtils;
18  import org.springframework.security.core.GrantedAuthority;
19  import org.springframework.security.core.authority.SimpleGrantedAuthority;
20  import org.springframework.security.core.userdetails.UserDetails;
21  import org.tailormap.api.persistence.Group;
22  import org.tailormap.api.persistence.User;
23  import org.tailormap.api.repository.GroupRepository;
24  
25  public class TailormapUserDetails implements UserDetails {
26    public record UDAdditionalProperty(String key, Boolean isPublic, Object value) implements Serializable {}
27  
28    @Serial
29    private static final long serialVersionUID = 2L;
30  
31    private final Collection<GrantedAuthority> authorities;
32    private final String username;
33    private final String password;
34    private final ZonedDateTime validUntil;
35    private final boolean enabled;
36  
37    private final List<UDAdditionalProperty> additionalProperties = new ArrayList<>();
38    private final List<UDAdditionalProperty> additionalGroupProperties = new ArrayList<>();
39  
40    public TailormapUserDetails(User user, GroupRepository groupRepository) {
41      authorities = new HashSet<>();
42      user.getGroups().stream()
43          .map(Group::getName)
44          .map(SimpleGrantedAuthority::new)
45          .forEach(authorities::add);
46  
47      user.getGroups().stream()
48          .map(Group::getAliasForGroup)
49          .filter(StringUtils::isNotBlank)
50          .map(SimpleGrantedAuthority::new)
51          .forEach(authorities::add);
52  
53      username = user.getUsername();
54      password = user.getPassword();
55      validUntil = user.getValidUntil();
56      enabled = user.isEnabled();
57  
58      user.getAdditionalProperties().stream()
59          .map(p -> new UDAdditionalProperty(p.getKey(), p.getIsPublic(), p.getValue()))
60          .forEach(additionalProperties::add);
61  
62      // For group properties, look in the database instead of user.getGroups(), so aliasForGroup is taken into
63      // account
64      groupRepository
65          .findAllById(
66              authorities.stream().map(GrantedAuthority::getAuthority).toList())
67          .stream()
68          .map(Group::getAdditionalProperties)
69          .filter(Objects::nonNull)
70          .flatMap(Collection::stream)
71          .map(p -> new UDAdditionalProperty(p.getKey(), p.getIsPublic(), p.getValue()))
72          .forEach(additionalGroupProperties::add);
73    }
74  
75    @Override
76    public Collection<? extends GrantedAuthority> getAuthorities() {
77      return authorities;
78    }
79  
80    @Override
81    public String getPassword() {
82      return password;
83    }
84  
85    @Override
86    public String getUsername() {
87      return username;
88    }
89  
90    @Override
91    public boolean isAccountNonExpired() {
92      return validUntil == null || validUntil.isAfter(ZonedDateTime.now(ZoneId.systemDefault()));
93    }
94  
95    @Override
96    public boolean isEnabled() {
97      return enabled;
98    }
99  
100   public List<UDAdditionalProperty> getAdditionalProperties() {
101     return additionalProperties;
102   }
103 
104   public List<UDAdditionalProperty> getAdditionalGroupProperties() {
105     return additionalGroupProperties;
106   }
107 
108   public boolean getBooleanUserProperty(String key) {
109     return additionalProperties.stream()
110         .filter(p -> p.key.equals(key))
111         .map(UDAdditionalProperty::value)
112         .map("true"::equals)
113         .findFirst()
114         .orElse(false);
115   }
116 }