use of com.disney.http.auth.client.signer.HttpSignatureSigner in project groovity by disney.
the class Ws method tag.
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Object tag(Map attributes, Closure body) throws Exception {
Object url = resolve(attributes, URL);
if (url == null) {
throw new RuntimeException("ws() requires 'url' attribute");
}
ScriptHelper context = getScriptHelper(body);
Map variables = context.getBinding().getVariables();
URI uri;
URIBuilder builder;
ArrayList<Header> headers;
Function handlerFunction;
Optional<UserPass> userPass;
Optional<HttpSignatureSigner> signer;
final AtomicReference openMessage = new AtomicReference<>();
try {
builder = new URIBuilder(url.toString());
bind(context, Uri.CURRENT_URI_BUILDER, builder);
headers = new ArrayList<Header>();
bind(context, com.disney.groovity.tags.Header.CURRENT_LIST_FOR_HEADERS, headers);
Credentials.acceptCredentials(variables);
Signature.acceptSigner(variables);
Object oldOut = get(context, OUT);
StringWriter sw = new StringWriter();
Object rval = null;
bind(context, OUT, sw);
try {
rval = body.call();
if (rval instanceof Writable) {
((Writable) rval).writeTo(sw);
}
} finally {
bind(context, OUT, oldOut);
userPass = Credentials.resolveCredentials(variables);
signer = Signature.resolveSigner(variables);
}
String val = sw.toString().trim();
if (val.length() > 0) {
openMessage.set(val);
} else if (rval != null) {
openMessage.set(rval);
}
uri = builder.build();
handlerFunction = (Function) get(body, Handler.HANDLER_BINDING);
} catch (URISyntaxException e1) {
throw new RuntimeException("Invalid URI " + url, e1);
} finally {
unbind(context, Uri.CURRENT_URI_BUILDER);
unbind(context, com.disney.groovity.tags.Header.CURRENT_LIST_FOR_HEADERS);
unbind(context, Handler.HANDLER_BINDING);
}
final Closure closer = resolve(attributes, CLOSE, Closure.class);
final Closure errorHandler = resolve(attributes, ERROR, Closure.class);
final Class messageFormat = resolve(attributes, MESSAGE, Class.class);
final Integer timeout = resolve(attributes, TIMEOUT, Integer.class);
final AtomicReference<WebSocket> socket = new AtomicReference<>();
ClientEndpointConfig.Builder configBuilder = ClientEndpointConfig.Builder.create();
Session session;
try {
session = getContainer().connectToServer(new Endpoint() {
@Override
public void onOpen(Session session, EndpointConfig config) {
try {
openCount.incrementAndGet();
if (timeout != null) {
session.setMaxIdleTimeout(timeout * 1000);
}
WebSocket ws = new WebSocket(session);
socket.set(ws);
ws.setName(uri.toString());
if (handlerFunction != null) {
ws.setMessageHandler(arg -> {
synchronized (handlerFunction) {
handlerFunction.apply(arg);
}
}, messageFormat);
}
if (openMessage.get() != null) {
ws.call(openMessage.get());
}
} catch (Exception e) {
log.log(Level.SEVERE, "Error opening web socket session " + uri, e);
}
}
@Override
public void onClose(Session session, CloseReason reason) {
try {
closeCount.incrementAndGet();
openSessions.remove(session);
if (closer != null) {
if (closer.getMaximumNumberOfParameters() > 0) {
closer.call(reason);
} else {
closer.call();
}
}
} catch (Exception e) {
log.log(Level.SEVERE, "Error closing web socket session " + uri, e);
}
}
@Override
public void onError(Session session, Throwable th) {
try {
errorCount.incrementAndGet();
if (errorHandler == null) {
throw th;
}
errorHandler.call(th);
} catch (Throwable e) {
Level logLevel = Level.WARNING;
if (th != e) {
log.log(logLevel, "Error handling error for web socket session " + uri, e);
} else if (th instanceof IOException) {
logLevel = Level.FINE;
}
log.log(logLevel, "WebSocket client error: " + uri, th);
}
}
}, configBuilder.configurator(new ClientEndpointConfig.Configurator() {
public void beforeRequest(Map<String, List<String>> reqHeaders) {
// copy programmatic headers
for (Header header : headers) {
List<String> hl = reqHeaders.get(header.getName());
if (hl == null) {
hl = new ArrayList<>();
reqHeaders.put(header.getName(), hl);
}
hl.add(header.getValue());
}
Map<String, Map<String, String>> allChallenges = null;
if (userPass.isPresent() || signer.isPresent()) {
allChallenges = getChallenges(uri, reqHeaders);
}
if (userPass.isPresent()) {
UserPass user = userPass.get();
if (allChallenges != null) {
List<String> auths = reqHeaders.get(AUTHORIZATION_HEADER);
if (auths == null) {
auths = new ArrayList<>();
reqHeaders.put(AUTHORIZATION_HEADER, auths);
}
if (allChallenges.containsKey("basic")) {
StringBuilder authBuilder = new StringBuilder(user.getUser());
authBuilder.append(":");
char[] pass = user.getPass();
for (char c : pass) {
authBuilder.append(c);
}
try {
auths.add("Basic " + printBase64Binary(authBuilder.toString().getBytes("UTF-8")));
} catch (UnsupportedEncodingException e) {
log.severe(e.getMessage());
}
}
if (allChallenges.containsKey("digest")) {
final String digestUri = uri.getPath() + ((uri.getRawQuery() != null) ? "?" + uri.getRawQuery() : "");
Map<String, String> digestChallenge = allChallenges.get("digest");
if (log.isLoggable(Level.FINE)) {
log.fine("Generating digest auth for " + digestChallenge.toString());
}
DigestAuthorization digestAuth = new DigestAuthorization();
digestAuth.setUsername(user.getUser());
digestAuth.setQop("auth");
digestAuth.setCnonce(String.valueOf(ThreadLocalRandom.current().nextLong(10000000, 999999999999l)));
digestAuth.setNonceCount("000001");
digestAuth.setUri(digestUri);
for (Entry<String, String> entry : digestChallenge.entrySet()) {
String k = entry.getKey();
String v = entry.getValue();
if ("nonce".equalsIgnoreCase(k)) {
digestAuth.setNonce(v);
} else if ("realm".equalsIgnoreCase(k)) {
digestAuth.setRealm(v);
} else if ("opaque".equalsIgnoreCase(k)) {
digestAuth.setOpaque(v);
}
}
String signingString;
try {
signingString = digestAuth.generateSigningString(user.getUser(), new String(user.getPass()), new AuthorizationRequest() {
@Override
public String getURI() {
return digestUri;
}
@Override
public String getMethod() {
return "GET";
}
@Override
public List<String> getHeaders(String name) {
return reqHeaders.get(name);
}
});
MessageDigest md5 = MessageDigest.getInstance("MD5");
digestAuth.setDigest(md5.digest(signingString.toString().getBytes()));
if (log.isLoggable(Level.FINE)) {
log.fine("Generated digest auth " + digestAuth.toString());
}
auths.add(digestAuth.toString());
} catch (NoSuchAlgorithmException e) {
log.severe("Missing MD5 " + e.getMessage());
}
}
}
}
if (signer.isPresent()) {
if (allChallenges.containsKey("signature")) {
HttpSignatureSigner sig = signer.get();
HttpGet signReq = createRequest(uri, reqHeaders);
List<Header> beforeHeaders = Arrays.asList(signReq.getAllHeaders());
try {
sig.process(signReq, null);
} catch (HttpException | IOException e) {
log.log(Level.SEVERE, "Error processing http signature", e);
}
Header[] afterHeaders = signReq.getAllHeaders();
for (Header h : afterHeaders) {
if (!beforeHeaders.contains(h)) {
List<String> hl = reqHeaders.get(h.getName());
if (hl == null) {
hl = new ArrayList<>();
reqHeaders.put(h.getName(), hl);
}
hl.add(h.getValue());
if (log.isLoggable(Level.FINE)) {
log.fine("Copied HTTP signature header " + h);
}
}
}
}
}
}
}).build(), uri);
} catch (Exception e) {
errorCount.incrementAndGet();
throw e;
}
openSessions.add(session);
String var = resolve(attributes, VAR, String.class);
if (var != null) {
context.getBinding().setVariable(var, socket.get());
}
return socket.get();
}
use of com.disney.http.auth.client.signer.HttpSignatureSigner in project groovity by disney.
the class TestSignatureAuth method testGeneralSettings.
@Test
public void testGeneralSettings() throws Exception {
HttpGet request = new HttpGet("http://localhost:8080/");
HttpClientContext localContext = new HttpClientContext();
HttpSignatureSigner signer = new HttpSignatureSigner();
String keyId = "apiUser123";
String keyValue = "someBase64Secret";
String headers = "(request-target) host x-date";
String algorithm = "hmac-sha256";
// check default header was set
Assert.assertEquals(AUTHORIZATION_HEADER, signer.getHeaderName());
// check all contents got set correctly
signer.setHeaderName(SIGNATURE_HEADER);
signer.setKeyId(keyId);
signer.setAlgorithm(algorithm);
signer.setKeyLoader(new KeyObjectKeyLoader(new SecretKeySpec(keyValue.getBytes(), "HmacSHA256")));
signer.process(request, localContext);
// no headers specified, should have added 'Date' header
Assert.assertEquals(signer.getHeaders().get(0), "Date");
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.process(request, localContext);
Assert.assertEquals(SIGNATURE_HEADER, signer.getHeaderName());
String authHeader = getAuthHeader(request);
String[] signatureParts = authHeader.split(",");
for (int i = 0; i < signatureParts.length; i++) {
String attributeString = (signatureParts[i]);
String[] attributeParts = attributeString.split("=");
String key = attributeParts[0];
String value = attributeParts[1];
if (key == "keyId") {
Assert.assertEquals(keyId, value);
} else if (key == "algorithm") {
Assert.assertEquals(algorithm, value);
} else if (key == "headers") {
Assert.assertEquals(headers, value);
}
}
}
use of com.disney.http.auth.client.signer.HttpSignatureSigner in project groovity by disney.
the class TestSignatureAuth method testMissingKeyId.
@Test(expected = HttpException.class)
public void testMissingKeyId() throws Exception {
HttpGet request = new HttpGet("http://localhost:8080/");
HttpClientContext localContext = new HttpClientContext();
HttpSignatureSigner signer = new HttpSignatureSigner();
signer.process(request, localContext);
}
use of com.disney.http.auth.client.signer.HttpSignatureSigner in project groovity by disney.
the class TestSignatureAuth method testRSA.
@Test
public void testRSA() throws Exception {
HttpGet request = new HttpGet("http://localhost:8080/");
HttpClientContext localContext = new HttpClientContext();
HttpSignatureSigner signer = new HttpSignatureSigner();
signer.setHeaderName(SIGNATURE_HEADER);
String keyId = "apiUser123";
String headers = "(request-target) host x-date";
KeyPair pair = KeyUtils.generateKeyPair();
PrivateKey privateKey = pair.getPrivate();
PublicKey publicKey = pair.getPublic();
KeyObjectKeyLoader privateKeyLoader = new KeyObjectKeyLoader(privateKey);
signer.setAlgorithm("rsa-sha256");
signer.setKeyId(keyId);
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.setKeyLoader(privateKeyLoader);
signer.process(request, localContext);
SignatureAuthorization testAuth = new SignatureAuthorization();
testAuth.setAlgorithm("rsa-sha256");
testAuth.setHeaders(signer.getHeaders());
String signingString = testAuth.generateSigningString(new ClientAuthorizationRequest(request));
byte[] encryptedString = signer.doAuthorization(request).getSignature();
boolean verify = verifyRsa("SHA256withRSA", publicKey, signingString, encryptedString);
Assert.assertTrue(verify);
// can choose algorithm
signer.setAlgorithm("rsa-md5");
signer.process(request, localContext);
encryptedString = signer.doAuthorization(request).getSignature();
verify = verifyRsa("MD5withRSA", publicKey, signingString, encryptedString);
Assert.assertTrue(verify);
// wrong keyid, not a key loader so no effect
signer.setAlgorithm("rsa-sha256");
signer.setKeyId("something else");
signer.process(request, localContext);
encryptedString = signer.doAuthorization(request).getSignature();
verify = verifyRsa("SHA256withRSA", publicKey, signingString, encryptedString);
Assert.assertTrue(verify);
// different headers
signer.setHeaders(Arrays.asList("host", "x-date"));
signer.process(request, localContext);
encryptedString = signer.doAuthorization(request).getSignature();
verify = verifyRsa("SHA256withRSA", publicKey, signingString, encryptedString);
Assert.assertFalse(verify);
// load plain key from file;
String location = "target/priv.pem";
File pemFile = new File(location);
URIParcel.put(pemFile.toURI(), pair);
URIParcel<KeyPair> pemParcel = new URIParcel<KeyPair>(KeyPair.class, pemFile.toURI());
signer = new HttpSignatureSigner();
signer.setHeaderName(SIGNATURE_HEADER);
signer.setKeyId("defaultValue");
signer.setAlgorithm("rsa-sha256");
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.setKeyPairLoader(pemParcel);
signingString = testAuth.generateSigningString(new ClientAuthorizationRequest(request));
encryptedString = signer.doAuthorization(request).getSignature();
verify = verifyRsa("SHA256withRSA", publicKey, signingString, encryptedString);
Assert.assertTrue(verify);
// try using a KeyStoreLoader
signer = new HttpSignatureSigner();
signer.setHeaderName(SIGNATURE_HEADER);
signer.setAlgorithm("rsa-sha256");
location = "target/testKeytool.store";
Map<String, Object> config = new HashMap<String, Object>();
config.put(KeyStoreValueHandler.KEYSTORE_PASSWORD, "rachel");
config.put(KeyStoreValueHandler.KEYSTORE_TYPE, "JCEKS");
URIParcel<KeyStore> parcel = new URIParcel<KeyStore>(KeyStore.class, new File(location).toURI(), config);
KeyChain chain = new KeyStoreKeyChainImpl(parcel, "".toCharArray());
KeyChainKeyLoader keystoreLoader = new KeyChainKeyLoader(chain);
keystoreLoader.setAlias("test");
signer.setKeyId("test");
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.setKeyLoader(keystoreLoader);
signer.process(request, localContext);
signingString = testAuth.generateSigningString(new ClientAuthorizationRequest(request));
encryptedString = signer.doAuthorization(request).getSignature();
// check again public key
KeyStore importedKeystore = parcel.call();
PublicKey loadedPublicKey = importedKeystore.getCertificate("test").getPublicKey();
verifyRsa("SHA256withRSA", loadedPublicKey, signingString, encryptedString);
Assert.assertTrue(verify);
}
use of com.disney.http.auth.client.signer.HttpSignatureSigner in project groovity by disney.
the class TestSignatureAuth method testHmac.
@Test
public void testHmac() throws Exception {
HttpGet request = new HttpGet("http://localhost:8080/");
HttpClientContext localContext = new HttpClientContext();
HttpSignatureSigner signer = new HttpSignatureSigner();
signer.setHeaderName(SIGNATURE_HEADER);
String keyId = "apiUser123";
String keyValue = "someBase64Secret";
String headers = "(request-target) host x-date";
String algorithm = "hmac-sha256";
KeyObjectKeyLoader hmacKey = new KeyObjectKeyLoader(algorithm, keyValue);
signer.setHeaderName(SIGNATURE_HEADER);
signer.setKeyId(keyId);
signer.setKeyLoader(hmacKey);
signer.setAlgorithm(algorithm);
signer.process(request, localContext);
SignatureAuthorization testAuth = new SignatureAuthorization();
testAuth.setHeaders(signer.getHeaders());
Assert.assertNotNull(signer.getHeaderName());
Assert.assertNotNull(getAuthHeader(request));
String signingString = testAuth.generateSigningString(new ClientAuthorizationRequest(request));
byte[] expectedResult = signHmac(algorithm, keyValue, signingString);
byte[] signature = signer.doAuthorization(request).getSignature();
Assert.assertArrayEquals(expectedResult, signature);
// bad signing string
Assert.assertFalse(Arrays.equals(signHmac(algorithm, keyValue, signingString + "invalid"), signature));
// wrong key
signer.setKeyLoader(new KeyObjectKeyLoader(algorithm, "differentKeyValue"));
signer.process(request, localContext);
signature = signer.doAuthorization(request).getSignature();
Assert.assertFalse("Wrong Key", Arrays.equals(expectedResult, signature));
// wrong algorithm
signer.setAlgorithm("hmac-md5");
signer.process(request, localContext);
signature = signer.doAuthorization(request).getSignature();
Assert.assertFalse("Wrong algorithm", Arrays.equals(expectedResult, signature));
// wrong headers
signer.setHeaders(Arrays.asList(headers.split(" ")));
signer.setAlgorithm(algorithm);
signer.setKeyLoader(hmacKey);
signer.process(request, localContext);
signature = signer.doAuthorization(request).getSignature();
Assert.assertFalse("Incorrect Headers", Arrays.equals(expectedResult, signature));
// wrong header order
signer.setHeaders(Arrays.asList("host (request-target) x-date"));
signer.process(request, localContext);
signature = signer.doAuthorization(request).getSignature();
Assert.assertFalse("Incorrect header order", Arrays.equals(expectedResult, signature));
}
Aggregations