Project

General

Profile

Download (3.85 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2021 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9
package eu.etaxonomy.cdm.api.security;
10

    
11
import java.security.SecureRandom;
12
import java.util.Base64;
13
import java.util.Base64.Encoder;
14
import java.util.Date;
15
import java.util.HashMap;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Optional;
19
import java.util.stream.Collectors;
20

    
21
import org.apache.log4j.Logger;
22
import org.springframework.stereotype.Component;
23

    
24
import eu.etaxonomy.cdm.model.permission.User;
25

    
26
/**
27
 * @author a.kohlbecker
28
 * @since Nov 3, 2021
29
 */
30
@Component
31
public class PasswordResetTokenStore implements IPasswordResetTokenStore {
32

    
33
    public  static final int TOKEN_LENGTH = 50;
34

    
35
    private static Logger logger = Logger.getLogger(PasswordResetTokenStore.class);
36

    
37
    private Map<String, PasswordResetRequest> tokenList = new HashMap<>();
38

    
39
    private Integer tokenLifetimeMinutes = null;
40

    
41
    @Override
42
    public PasswordResetRequest create(User user) {
43
        clearExpiredTokens();
44
        assert user != null;
45
        assert !user.getEmailAddress().isEmpty();
46
        PasswordResetRequest token = new PasswordResetRequest(user.getUsername(), user.getEmailAddress(), generateRandomToken(), getTokenLifetimeMinutes());
47
        tokenList.put(token.getToken(), token);
48
        return token;
49
    }
50

    
51
    private String generateRandomToken() {
52
        SecureRandom random = new SecureRandom();
53
        byte bytes[] = new byte[TOKEN_LENGTH];
54
        random.nextBytes(bytes);
55
        Encoder encoder = Base64.getUrlEncoder().withoutPadding();
56
        String token = encoder.encodeToString(bytes);
57
        return token;
58
    }
59

    
60
    @Override
61
    public Optional<PasswordResetRequest> findResetRequest(String token) {
62
        clearExpiredTokens();
63
        PasswordResetRequest resetRequest = tokenList.get(token);
64
        if(isEligibleResetRequest(resetRequest)) {
65
            return Optional.of(resetRequest);
66
        }
67
        return Optional.empty();
68
    }
69

    
70
    @Override
71
    public boolean isEligibleToken(String token) {
72
        clearExpiredTokens();
73
        PasswordResetRequest resetRequest = tokenList.get(token);
74
        return isEligibleResetRequest(resetRequest);
75
    }
76

    
77
    private boolean isEligibleResetRequest(PasswordResetRequest resetRequest) {
78
        if(resetRequest == null) {
79
            logger.error("PasswordResetRequest must not be null");
80
            return false;
81
        }
82
        if(resetRequest.getExpiryDate().before(new Date())) {
83
            tokenList.remove(resetRequest.getToken());
84
            logger.info("Token is expired, and has been deleted now.");
85
            return false;
86
        }
87
        return true;
88
    }
89

    
90
    /**
91
     * To be called periodically to remove expired tokens.
92
     *
93
     * @return the number of expired tokens that have been cleared
94
     */
95
    private int clearExpiredTokens() {
96
        Date now = new Date();
97
        List<String> expiredTokens = tokenList.values().stream().filter(t -> t.getExpiryDate().before(now)).map(t -> t.getToken()).collect(Collectors.toList());
98
        expiredTokens.stream().forEach(tstr -> tokenList.remove(tstr));
99
        return expiredTokens.size();
100
    }
101

    
102
    /**
103
     * Removes the token from the store
104
     *
105
     * @param token
106
     * @return true if the token to be remove has existed, otherwise false
107
     */
108
    @Override
109
    public boolean remove(String token) {
110
        clearExpiredTokens();
111
        return tokenList.remove(token) != null;
112
    }
113

    
114
    public int getTokenLifetimeMinutes() {
115
        return this.tokenLifetimeMinutes != null ? this.tokenLifetimeMinutes : TOKEN_LIFETIME_MINUTES_DEFAULT;
116
    }
117

    
118
    @Override
119
    public void setTokenLifetimeMinutes(int tokenLifetimeMinutes) {
120
        this.tokenLifetimeMinutes = tokenLifetimeMinutes;
121
    }
122

    
123
}
(3-3/3)