package com.nitorcreations.willow.auth;

import javax.inject.Singleton;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Singleton
public class PublicKeyAuthenticationFilter extends BasicHttpAuthenticationFilter {
  private static final Logger log = LoggerFactory.getLogger(PublicKeyAuthenticationFilter.class);

  private static final String scheme = "PUBLICKEY";
  public PublicKeyAuthenticationFilter() {
    this.setAuthcScheme(scheme);
    this.setAuthzScheme(scheme);
  }
  @Override
  protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
    String authorizationHeader = getAuthzHeader(request);
    if (authorizationHeader == null || authorizationHeader.length() == 0) {
      return createToken("", null, null, request);
    }

    if (log.isDebugEnabled()) {
        log.debug("Attempting to execute login with headers [" + authorizationHeader + "]");
    }
    
    String[] header = authorizationHeader.split("\\s+");
    if (header.length < 3 || !scheme.equals(header[0].toUpperCase())) {
      return createToken("", null, null, request);
    }
    String unameNow = Base64.decodeToString(header[1]);
    String username = unameNow.split(":")[0];
    PublicKeyAuthenticationToken token = createToken(username, Base64.decode(header[1]), Base64.decode(header[2]), request);
    for (int i=3; i<header.length;i++) {
      token.addSignature(Base64.decode(header[i]));
    }
    return token;
  }
  protected PublicKeyAuthenticationToken createToken(String username, byte[] sign, byte[] signature, ServletRequest request) {
    return new PublicKeyAuthenticationToken(username, sign, signature, getHost(request));
  }
}

@@ -34,16 +34,43 @@
 .auth;%0A%0A
+import java.util.TreeSet;%0A%0A
 import j
@@ -92,16 +92,16 @@
 gleton;%0A
-
 import j
@@ -579,17 +579,76 @@
 class);%0A
+  private final TreeSet%3CLong%3E timeStamps = new TreeSet%3C%3E();
 %0A
-
   privat
@@ -1436,16 +1436,18 @@
   String
+%5B%5D
  unameNo
@@ -1482,16 +1482,27 @@
 ader%5B1%5D)
+.split(%22:%22)
 ;%0A    St
@@ -1529,23 +1529,446 @@
 eNow
-.split(%22:%22)%5B0%5D;
+%5B0%5D;%0A    long timestamp = Long.parseLong(unameNow%5B1%5D);%0A    long currentTime = System.currentTimeMillis();%0A    long wStart = currentTime - 15000;%0A    long wEnd = currentTime + 15000;%0A    if (!((timestamp %3E wStart) && (timestamp %3C wEnd)) %7C%7C timeStamps.contains(timestamp)) %7B%0A      return createToken(%22%22, null, null, request);%0A    %7D%0A    timeStamps.add(timestamp);%0A    while (timeStamps.first() %3C wStart) %7B%0A      timeStamps.pollFirst();%0A    %7D
 %0A   

Add check for timestamp - needs to be in 30s window from now (+-15s) and needs to not have seen before