package io.fathom.cloud.server.auth;
import io.fathom.cloud.protobuf.CloudCommons.Token;
import io.fathom.cloud.protobuf.CloudCommons.TokenInfo;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.keyczar.Signer;
import org.keyczar.exceptions.KeyczarException;
import org.keyczar.util.Base64Coder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Strings;
import com.google.protobuf.ByteString;
@Singleton
public class SharedSecretTokenService implements TokenService, TokenEncoder {
private static final Logger log = LoggerFactory.getLogger(SharedSecretTokenService.class);
public static final String KEYSTORE_ID = "token_sign";
@Inject
SharedKeystore keystore;
private Signer signer;
@Override
public TokenInfo findValidToken(String tokenString) {
if (Strings.isNullOrEmpty(tokenString)) {
return null;
}
try {
byte[] tokenBytes = Base64Coder.decodeWebSafe(tokenString);
Token token = Token.parseFrom(tokenBytes);
TokenInfo tokenInfo = token.getTokenInfo();
byte[] plaintext = tokenInfo.toByteArray();
if (!getSigner().verify(plaintext, token.getSignature().toByteArray())) {
log.debug("Token signature verification failed");
return null;
}
if (TokenAuth.hasExpired(tokenInfo)) {
log.debug("Token has expired");
return null;
}
return tokenInfo;
} catch (Exception e) {
log.debug("Error during token validation", e);
return null;
}
}
@Override
public String encodeToken(TokenInfo tokenInfo) {
Token.Builder token = Token.newBuilder();
token.setTokenInfo(tokenInfo);
byte[] plaintext = tokenInfo.toByteArray();
byte[] signature;
try {
signature = getSigner().sign(plaintext);
} catch (KeyczarException e) {
throw new IllegalStateException("Error signing token", e);
}
log.info("Token plaintext size {} signature size {}", plaintext.length, signature.length);
token.setSignature(ByteString.copyFrom(signature));
String encoded = Base64Coder.encodeWebSafe(token.build().toByteArray());
log.info("Token encoded size {}", encoded.length());
return encoded;
}
private synchronized Signer getSigner() throws KeyczarException {
if (signer == null) {
this.signer = keystore.buildSigner(KEYSTORE_ID);
}
return signer;
}
}