supereagle / experiences

Summary of practical experience in work.
2 stars 0 forks source link

MAC of Auth Server implemented in Java #21

Closed supereagle closed 7 years ago

supereagle commented 7 years ago

References

supereagle commented 7 years ago

TokenGenerator.java

package com.auth.demo;

import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.Date;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

public class TokenGenerator {
    private final long LIFETIME = 1000000; // The lifetime of token is 1000s.
    // The secret key can be dynamically generated.
    private final String SECRET_KEY = "Auth-d1mo"; 
    private final Encoder ENCODER = Base64.getEncoder();
    private final Decoder DECODER = Base64.getDecoder();
    private final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
    private final int SIG_LEN = 40; // The length of encoded token data.

    // The generated token has 2 parts: token data encoded by Base64 + token
    // data encoded by HmacSHA1 algorithm.
    public String genToken(TokenArgs args) {
        TokenData tokenData = getTokenDataFromTokenArgs(args);
        String payload = JSON.toJSONString(tokenData);

        try {
            return ENCODER.encodeToString(payload.getBytes(StandardCharsets.UTF_8))
                    + encodeHmacSHA(payload, SECRET_KEY);
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }

        return null;
    }

    public boolean verifyToken(String token) {
        String payload = new String(DECODER.decode(token.substring(0, token.length() - SIG_LEN)),
                StandardCharsets.UTF_8);
        String sig = token.substring(token.length() - SIG_LEN, token.length());

        TokenData tokenData = JSON.parseObject(payload, TokenData.class);
        if (tokenData != null) {
            if (tokenData.getExpires() < new Date().getTime()) {
                return false;
            }

            String expectedSig = null;
            try {
                expectedSig = encodeHmacSHA(payload, SECRET_KEY);
            } catch (SignatureException e) {
                e.printStackTrace();
                return false;
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return false;
            } catch (InvalidKeyException e) {
                e.printStackTrace();
                return false;
            }

            if (!sig.equals(expectedSig)) {
                return false;
            }

            return true;
        }

        return false;
    }

    private String encodeHmacSHA(String payload, String key)
            throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
        SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
        Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
        mac.init(signingKey);
        return new HexBinaryAdapter().marshal(mac.doFinal(payload.getBytes()));
    }

    private TokenData getTokenDataFromTokenArgs(TokenArgs args) {
        // Verify the user info
        if (args.getUsername() != "admin" || args.getPassword() != "admin") {
            return null;
        }

        return new TokenData(args.getResource(), new Date().getTime() + LIFETIME);
    }
}
supereagle commented 7 years ago

TokenArgs.java

package com.auth.demo;

public class TokenArgs {
    private String username;
    private String password;
    private String resource;

    public TokenArgs(String username, String password, String resource) {
        this.username = username;
        this.password = password;
        this.resource = resource;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getResource() {
        return resource;
    }

    public void setResource(String resource) {
        this.resource = resource;
    }
}

TokenData.java

package com.auth.demo;

import java.util.UUID;

public class TokenData {
    private String resource;
    private UUID salt; // Dynamical salt ensures every token is different.
    private Long expires;

    public TokenData(String resource, Long expires) {
        this.resource = resource;
        this.salt = UUID.randomUUID();
        this.expires = expires;
    }

    public String getResource() {
        return resource;
    }

    public void setResource(String resource) {
        this.resource = resource;
    }

    public UUID getSalt() {
        return salt;
    }

    public void setSalt(UUID salt) {
        this.salt = salt;
    }

    public Long getExpires() {
        return expires;
    }

    public void setExpires(Long expires) {
        this.expires = expires;
    }
}