package org.qrone.login;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.qrone.util.Digest;
import org.qrone.util.Hex;
public class AccessToken {
public static final String MASTER = "X";
public static final String GRANT = "G";
public static final String PAY = "P";
public static final String WRITEC = "D";
public static final String WRITE = "W";
public static final String READC = "C";
public static final String READ = "R";
public static final String ADD = "A";
public static final String DEVICE = "D";
public static final String BROWSER = "B";
// Token-[Scope1][:[Scope2][:[Scope3]...]]
// .ID-[userID]
// [.asID-[asID]]
// [.Sign-[Timestamp]:[Sign]]
private String id;
private String asid;
private Set<String> scopes;
private long timestamp;
private byte[] sign;
private AccessToken(){
}
public AccessToken(String id, String scope){
this(id, null, scopeSet(scope));
}
public AccessToken(String id, Set<String> scopes){
this(id, null, scopes);
}
public AccessToken(String id, String asid, String scope){
this(id, asid, scopeSet(scope));
}
public AccessToken(String id, String asid, Set<String> scopes){
this.id = id;
this.asid = asid;
this.scopes = scopes;
}
public void sign(UUID signersecret){
this.timestamp = System.currentTimeMillis();
this.sign = calcSign(signersecret.toString());
}
public boolean validate(UUID signersecret, String scope, long millis){
if(validate(signersecret, scope) && (System.currentTimeMillis() - timestamp) < millis){
return true;
}
return false;
}
public boolean validate(UUID signersecret, String scope){
if(validate(signersecret)){
if(scopes.contains(scope) || scopes.contains("X")){
return true;
}
if(scope.equals("R") && scopes.contains("C")){
return true;
}
if(scope.equals("W") && scopes.contains("D")){
return true;
}
}
return false;
}
public boolean validate(UUID signersecret){
return Arrays.equals(sign, calcSign(signersecret.toString()));
}
private byte[] calcSign(String secret){
try {
return Digest.digest("SHA1", (toTokenString(secret)).getBytes());
} catch (NoSuchAlgorithmException e) {}
return new byte[0];
}
public static AccessToken parse(String tokenString){
if(tokenString == null) return null;
AccessToken t = new AccessToken();
try{
String[] s = tokenString.split("\\.");
Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < s.length; i++) {
map.put(s[i].substring(0, s[i].indexOf("-")), s[i]);
}
String token = map.get("Token");
if(token != null){
String[] sc = token.substring("Token-".length()).split("\\:");
t.scopes = new HashSet<String>();
for (int i = 0; i < sc.length; i++) {
t.scopes.add(Hex.hex2str(sc[i]));
}
}
String id = map.get("ID");
if(token != null){
t.id = id;
}
String asid = map.get("asID");
if(asid != null){
t.asid = asid.substring(2);
}
String sign = map.get("Sign");
if(sign != null){
String[] ss = sign.substring("Sign-".length()).split("\\:");
t.timestamp = Hex.hex2long(ss[0]);
t.sign = Hex.hex2bytearray(ss[1]);
}
return t;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
private static Set<String> scopeSet(String scope){
Set<String> set = new HashSet<String>();
set.add(scope);
return set;
}
public static String uniqueid(){
return Hex.long2hex(System.currentTimeMillis())
+ Hex.double2hex(Math.random());
}
public String getId(){
return id;
}
public long getTimestamp(){
return timestamp;
}
private String toBodyString(){
StringBuilder sb = new StringBuilder();
sb.append("Token-");
boolean first = true;
if(scopes != null){
for (Iterator<String> iter = scopes.iterator(); iter.hasNext();) {
if(!first){
sb.append(":");
}
sb.append(Hex.str2hex(iter.next()));
first = false;
}
}
if(id != null){
sb.append(".");
sb.append(id.toString());
}
if(asid != null){
sb.append(".as");
sb.append(asid.toString());
}
return sb.toString();
}
private String toTokenString(String signstr){
StringBuilder sb = new StringBuilder();
sb.append(toBodyString());
sb.append(".Sign-");
sb.append(Hex.long2hex(timestamp));
sb.append(":");
sb.append(signstr);
return sb.toString();
}
public String toString(){
if(sign != null){
return toTokenString(Hex.bytearray2hex(sign));
}
return toBodyString();
}
public static void main(String[] args){
AccessToken t1 = ID.generateAccessToken(UUID.randomUUID(), "SCOPE");
System.out.println(t1.toString());
AccessToken t11 = AccessToken.parse(t1.toString());
System.out.println(t11.toString());
AccessToken t2 = ID.generateAccessToken(UUID.randomUUID(), "SCOPE");
System.out.println(t2.toString());
AccessToken t22 = AccessToken.parse(t2.toString());
System.out.println(t22.toString());
UUID secret = UUID.randomUUID();
t1.sign(secret);
System.out.println(t1.toString());
System.out.println("length: " + t1.toString().length());
AccessToken t3 = AccessToken.parse(t1.toString());
System.out.println(t3.toString());
System.out.println(t3.validate(secret));
System.out.println(t3.validate(secret, "SCOPE"));
System.out.println(t3.validate(secret, "SCOPE", 1000));
}
}