package net.davidvoid.thor.lightning.service.security;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import net.davidvoid.thor.lightning.exception.AuthenticationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

/**
 * Created by david on 4/26/16.
 */
@Component
public class JwtAuthenticationService {
    static Log logger = LogFactory.getLog(JwtAuthenticationService.class);

    String secretKey = null;
    
    public JwtAuthenticationService() {
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("config/key.hmac");
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        try {
            secretKey = reader.readLine();
        } catch (IOException e) {
            logger.fatal("unable to read HMAC key");
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                logger.fatal("failed to close file");
            }
        }
    }

    public Authentication authenticate(String jwtToken) {
        try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
            String username = claims.getBody().getSubject();
            if (username == null) throw new AuthenticationException("no subject present");

            List<GrantedAuthority> roles = new ArrayList<>();
            roles.add(new SimpleGrantedAuthority("USER"));
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, "", roles);
            return token;

        } catch (JwtException e) {
            throw new AuthenticationException("invalid JWT token", e);
        }
    }
    
    public String getToken(String username) {
        return Jwts.builder().setSubject(username).signWith(SignatureAlgorithm.HS512, secretKey).compact();
    }
}

@@ -384,22 +384,116 @@
 va.util.
-List;%0A
+Date;%0Aimport java.util.List;%0Aimport java.util.Map;%0A%0Aimport net.davidvoid.thor.lightning.entity.User;
 %0Aimport 
@@ -555,16 +555,69 @@
 ception;
+%0Aimport net.davidvoid.thor.lightning.util.MapLiteral;
 %0A%0Aimport
@@ -1189,16 +1189,61 @@
 .class);
+%0A    static long EXPIRATION_TIME = 20 * 1000;
 %0A%0A    St
@@ -2146,16 +2146,306 @@
 esent%22);
+%0A            %0A            Date issuedDate = claims.getBody().getIssuedAt();%0A            Date current = new Date();%0A            long offset = current.getTime() - issuedDate.getTime();%0A            if (offset %3C 0 %7C%7C offset %3E EXPIRATION_TIME) throw new AuthenticationException(%22token expired%22);
 %0A%0A      
@@ -2862,77 +2862,233 @@
 ken(
-String username) %7B%0A        return Jwts.builder().setSubject(username)
+User user) %7B%0A        Map%3CString, Object%3E additional_claims = MapLiteral.map(%22uid%22, user.getId());%0A%0A        return Jwts.builder().setClaims(additional_claims).setSubject(user.getName()).setIssuedAt(new Date())%0A                
 .sig

add token expiration mechanism