Joaquín Reñé
2022-03-10 d535429a2f18c82de7716076a8065f6ad95f0483
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package net.curisit.securis.utils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import net.curisit.integrity.commons.Utils;
import net.curisit.securis.services.ApiResource;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jboss.resteasy.util.Base64;
@ApplicationScoped
public class TokenHelper {
    private static final Logger LOG = LogManager.getLogger(TokenHelper.class);
    /**
     * Period before token expires, set in hours.
     */
    private static int VALID_TOKEN_PERIOD = 24;
    public static final String TOKEN_HEADER_PÀRAM = "X-SECURIS-TOKEN";
    @Inject
    public TokenHelper() {
    }
    private static byte[] seed = "S3Cur15S33dForT0k3nG3n3r@tion".getBytes();
    /**
     * Generate a token encoded in Base64 for user passed as parameter and
     * taking the current moment as token timestamp
     * 
     * @param user
     * @return
     */
    public String generateToken(String user) {
        return generateToken(user, new Date());
    }
    public String generateToken(String user, Date date) {
        try {
            String secret = generateSecret(user, date);
            StringBuffer sb = new StringBuffer();
            sb.append(secret);
            sb.append(' ');
            sb.append(user);
            sb.append(' ');
            sb.append(Utils.toIsoFormat(date));
            return Base64.encodeBytes(sb.toString().getBytes("utf-8"));
        } catch (NoSuchAlgorithmException e) {
            LOG.error("Error generating SHA-256 hash", e);
        } catch (UnsupportedEncodingException e) {
            LOG.error("Error generating SHA-256 hash", e);
        }
        return null;
    }
    private String generateSecret(String user, Date date) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        MessageDigest mDigest = MessageDigest.getInstance("SHA-256");
        mDigest.update(seed, 0, seed.length);
        byte[] userbytes = user.getBytes("utf-8");
        mDigest.update(userbytes, 0, userbytes.length);
        byte[] isodate = Utils.toIsoFormat(date).getBytes();
        mDigest.update(isodate, 0, isodate.length);
        BigInteger i = new BigInteger(1, mDigest.digest());
        String secret = String.format("%1$064x", i);
        return secret;
    }
    /**
     * Check if passed token is still valid, It use to check if token is expired
     * the attribute VALID_TOKEN_PERIOD (in hours)
     * 
     * @param token
     * @return
     */
    public boolean isTokenValid(String token) {
        try {
            String tokenDecoded = new String(Base64.decode(token));
            String[] parts = StringUtils.split(tokenDecoded, ' ');
            if (parts == null || parts.length < 3) {
                return false;
            }
            String secret = parts[0];
            String user = parts[1];
            Date date = Utils.toDateFromIso(parts[2]);
            if (date.getTime() > 0 || !user.equals(ApiResource.API_CLIENT_USERNAME)) {
                if (new Date().after(new Date(date.getTime() + VALID_TOKEN_PERIOD * 60 * 60 * 1000))) {
                    return false;
                }
            } // else: It's a securis-client API call
            String newSecret = generateSecret(user, date);
            return newSecret.equals(secret);
        } catch (IOException e) {
            LOG.error("Error decoding Base64 token", e);
        } catch (NoSuchAlgorithmException e) {
            LOG.error("Error generation secret to compare with", e);
        }
        return false;
    }
    public String extractUserFromToken(String token) {
        try {
            if (token == null) {
                return null;
            }
            String tokenDecoded = new String(Base64.decode(token));
            String[] parts = StringUtils.split(tokenDecoded, ' ');
            if (parts == null || parts.length < 3) {
                return null;
            }
            String user = parts[1];
            return user;
        } catch (IOException e) {
            LOG.error("Error decoding Base64 token", e);
        }
        return null;
    }
    public Date extractDateCreationFromToken(String token) {
        try {
            String tokenDecoded = new String(Base64.decode(token));
            String[] parts = StringUtils.split(tokenDecoded, ' ');
            if (parts == null || parts.length < 3) {
                return null;
            }
            Date date = Utils.toDateFromIso(parts[2]);
            return date;
        } catch (IOException e) {
            LOG.error("Error decoding Base64 token", e);
        }
        return null;
    }
    public static void main(String[] args) throws IOException {
        // client token:
        // OTk3ODRiMzY5NzQ5MWI5NmYyZGQyODRiYjY2ZTU2YzdmMTZjYzM3YTY3N2ExM2M3ODI2MjU5ZTMzOTIyYjUzNSBfY2xpZW50IDE5NzAtMDEtMDFUMDA6NTk6NTkuOTk5KzAxMDA=
        // OTk3ODRiMzY5NzQ5MWI5NmYyZGQyODRiYjY2ZTU2YzdmMTZjYzM3YTY3N2ExM2M3ODI2MjU5ZTMzOTIyYjUzNSBfY2xpZW50IDE5NzAtMDEtMDFUMDA6NTk6NTkuOTk5KzAxMDA=
        String t = new TokenHelper().generateToken("_client", new Date(-1));
        System.out.println("client token: " + t);
        System.out.println("client token: " + new String(Base64.decode(t)));
        System.out.println("is valid client token: " + new TokenHelper().isTokenValid(t));
    }
}