Java tutorial
/* * **************************************************************************** * Cloud Foundry * Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved. * * This product is licensed to you under the Apache License, Version 2.0 (the "License"). * You may not use this product except in compliance with the License. * * This product includes a number of subcomponents with * separate copyright notices and license terms. Your use of these * subcomponents is subject to the terms and conditions of the * subcomponent's license, as noted in the LICENSE file. * **************************************************************************** */ package org.cloudfoundry.identity.uaa.oauth.jwk; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.codec.binary.Base64; import org.apache.commons.collections.map.HashedMap; import org.cloudfoundry.identity.uaa.oauth.KeyInfo; import org.cloudfoundry.identity.uaa.oauth.token.VerificationKeyResponse; import org.cloudfoundry.identity.uaa.util.JsonUtils; import org.junit.Test; import java.math.BigInteger; import java.security.PublicKey; import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.cloudfoundry.identity.uaa.oauth.jwk.JsonWebKey.KeyType.RSA; import static org.cloudfoundry.identity.uaa.oauth.jwk.JsonWebKey.KeyUse.sig; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; public class RsaJsonWebKeyTests { public static final String ISSUER = "http://localhost:8080/issuer"; @Test public void create_key_from_pem_string() { Base64 base64 = new Base64(true); KeyInfo keyInfo = new KeyInfo(); keyInfo.setKeyId("id"); keyInfo.setSigningKey(sampleRsaPrivateKey); assertEquals("RSA", keyInfo.getType()); assertNotNull(keyInfo.getVerifier()); PublicKey pk = keyInfo.getRsaPublicKey(); JsonWebKey key = JsonWebKeyHelper.fromPEMPrivateKey(keyInfo.getVerifierKey()).setKid("id"); assertEquals(RSA, key.getKty()); assertEquals("RSA", key.getKeyProperties().get("kty")); assertEquals("id", key.getKid()); assertEquals(sig, key.getUse()); assertEquals("sig", key.getKeyProperties().get("use")); assertNotNull(key.getValue()); BigInteger exponent = ((RSAPublicKey) pk).getPublicExponent(); BigInteger modulus = ((RSAPublicKey) pk).getModulus(); assertEquals(base64.encodeAsString(exponent.toByteArray()), key.getKeyProperties().get("e")); assertEquals(base64.encodeAsString(modulus.toByteArray()), key.getKeyProperties().get("n")); } @Test public void create_key_from_public_pem_string() { Base64 base64 = new Base64(true); KeyInfo keyInfo = new KeyInfo(); keyInfo.setKeyId("id"); keyInfo.setSigningKey(sampleRsaPrivateKey); assertEquals("RSA", keyInfo.getType()); assertNotNull(keyInfo.getVerifier()); PublicKey pk = keyInfo.getRsaPublicKey(); JsonWebKey key = JsonWebKeyHelper.fromPEMPublicKey(KeyInfo.pemEncodePublicKey(pk)).setKid("id"); assertEquals(RSA, key.getKty()); assertEquals("RSA", key.getKeyProperties().get("kty")); assertEquals("id", key.getKid()); assertEquals(sig, key.getUse()); assertEquals("sig", key.getKeyProperties().get("use")); assertNotNull(key.getValue()); BigInteger exponent = ((RSAPublicKey) pk).getPublicExponent(); BigInteger modulus = ((RSAPublicKey) pk).getModulus(); assertEquals(base64.encodeAsString(exponent.toByteArray()), key.getKeyProperties().get("e")); assertEquals(base64.encodeAsString(modulus.toByteArray()), key.getKeyProperties().get("n")); } @Test public void deserialize_azure_keys() { deserialize_azure_keys(sampleRsaKeys); } @Test public void ensure_that_duplicates_are_removed() { JsonWebKeySet<JsonWebKey> keys = JsonUtils.readValue(sampleRsaKeys, new TypeReference<JsonWebKeySet<JsonWebKey>>() { }); List<JsonWebKey> list = new ArrayList<>(keys.getKeys()); list.addAll(keys.getKeys()); assertEquals(6, list.size()); keys = new JsonWebKeySet<>(list); deserialize_azure_keys(JsonUtils.writeValueAsString(keys)); } @Test public void ensure_that_duplicates_get_the_last_object() { JsonWebKeySet<JsonWebKey> keys = JsonUtils.readValue(sampleRsaKeys, new TypeReference<JsonWebKeySet<JsonWebKey>>() { }); List<JsonWebKey> list = new ArrayList<>(keys.getKeys()); list.addAll(keys.getKeys()); assertEquals(6, list.size()); Map<String, Object> p = new HashedMap(list.get(5).getKeyProperties()); p.put("issuer", ISSUER); list.add(new VerificationKeyResponse(p)); assertEquals(7, list.size()); keys = new JsonWebKeySet<>(list); keys = deserialize_azure_keys(JsonUtils.writeValueAsString(keys)); assertEquals(ISSUER, keys.getKeys().get(2).getKeyProperties().get("issuer")); } @Test public void test_required_properties() { Map<String, Object> map = new HashMap(); test_create_with_error(map); map.put("kty", "invalid"); test_create_with_error(map); map.put("kty", "RSA"); new VerificationKeyResponse(map); } @Test public void test_equals() { Map<String, Object> p1 = new HashMap<>(); p1.put("kty", "RSA"); Map<String, Object> p2 = new HashMap<>(p1); assertEquals(new VerificationKeyResponse(p1), new VerificationKeyResponse(p2)); p1.put("kid", "id"); assertNotEquals(new VerificationKeyResponse(p1), new VerificationKeyResponse(p2)); p2.put("kid", "id"); assertEquals(new VerificationKeyResponse(p1), new VerificationKeyResponse(p2)); p1.put("issuer", "issuer1"); p2.put("issuer", "issuer2"); assertEquals(new VerificationKeyResponse(p1), new VerificationKeyResponse(p2)); p1.remove("kid"); p2.remove("kid"); assertNotEquals(new VerificationKeyResponse(p1), new VerificationKeyResponse(p2)); p2.put("issuer", "issuer1"); assertEquals(new VerificationKeyResponse(p1), new VerificationKeyResponse(p2)); } public void test_create_with_error(Map p) { try { new VerificationKeyResponse(p); fail("Creation of key with properties:" + p + " should fail."); } catch (IllegalArgumentException x) { } } public JsonWebKeySet<JsonWebKey> deserialize_azure_keys(String json) { JsonWebKeySet<JsonWebKey> keys = JsonUtils.readValue(json, new TypeReference<JsonWebKeySet<JsonWebKey>>() { }); assertNotNull(keys); assertNotNull(keys.getKeys()); assertEquals(3, keys.getKeys().size()); for (JsonWebKey key : keys.getKeys()) { assertNotNull(key); assertNotNull(JsonWebKey.getRsaPublicKey(key)); } return keys; } protected static final String sampleRsaPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n" + "MIICXgIBAAKBgQDfTLadf6QgJeS2XXImEHMsa+1O7MmIt44xaL77N2K+J/JGpfV3\n" + "AnkyB06wFZ02sBLB7hko42LIsVEOyTuUBird/3vlyHFKytG7UEt60Fl88SbAEfsU\n" + "JN1i1aSUlunPS/NCz+BKwwKFP9Ss3rNImE9Uc2LMvGy153LHFVW2zrjhTwIDAQAB\n" + "AoGBAJDh21LRcJITRBQ3CUs9PR1DYZPl+tUkE7RnPBMPWpf6ny3LnDp9dllJeHqz\n" + "a3ACSgleDSEEeCGzOt6XHnrqjYCKa42Z+Opnjx/OOpjyX1NAaswRtnb039jwv4gb\n" + "RlwT49Y17UAQpISOo7JFadCBoMG0ix8xr4ScY+zCSoG5v0BhAkEA8llNsiWBJF5r\n" + "LWQ6uimfdU2y1IPlkcGAvjekYDkdkHiRie725Dn4qRiXyABeaqNm2bpnD620Okwr\n" + "sf7LY+BMdwJBAOvgt/ZGwJrMOe/cHhbujtjBK/1CumJ4n2r5V1zPBFfLNXiKnpJ6\n" + "J/sRwmjgg4u3Anu1ENF3YsxYabflBnvOP+kCQCQ8VBCp6OhOMcpErT8+j/gTGQUL\n" + "f5zOiPhoC2zTvWbnkCNGlqXDQTnPUop1+6gILI2rgFNozoTU9MeVaEXTuLsCQQDC\n" + "AGuNpReYucwVGYet+LuITyjs/krp3qfPhhByhtndk4cBA5H0i4ACodKyC6Zl7Tmf\n" + "oYaZoYWi6DzbQQUaIsKxAkEA2rXQjQFsfnSm+w/9067ChWg46p4lq5Na2NpcpFgH\n" + "waZKhM1W0oB8MX78M+0fG3xGUtywTx0D4N7pr1Tk2GTgNw==\n" + "-----END RSA PRIVATE KEY-----"; protected static final String sampleRsaKeys = "{\n" + " \"keys\": [\n" + " {\n" + " \"e\": \"AQAB\",\n" + " \"issuer\": \"https://login.microsoftonline.com/9bc40aaf-e150-4c30-bb3c-a8b3b677266e/v2.0\",\n" + " \"kid\": \"YbRAQRYcE_motWVJKHrwLBbd_9s\",\n" + " \"kty\": \"RSA\",\n" + " \"n\": \"vbcFrj193Gm6zeo5e2_y54Jx49sIgScv-2JO-n6NxNqQaKVnMkHcz-S1j2FfpFngotwGMzZIKVCY1SK8SKZMFfRTU3wvToZITwf3W1Qq6n-h-abqpyJTaqIcfhA0d6kEAM5NsQAKhfvw7fre1QicmU9LWVWUYAayLmiRX6o3tktJq6H58pUzTtx_D0Dprnx6z5sW-uiMipLXbrgYmOez7htokJVgDg8w-yDFCxZNo7KVueUkLkxhNjYGkGfnt18s7ZW036WoTmdaQmW4CChf_o4TLE5VyGpYWm7I_-nV95BBvwlzokVVKzveKf3l5UU3c6PkGy-BB3E_ChqFm6sPWw\",\n" + " \"use\": \"sig\",\n" + " \"x5c\": [\n" + " \"MIIC4jCCAcqgAwIBAgIQfQ29fkGSsb1J8n2KueDFtDANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE2MDQxNzAwMDAwMFoXDTE4MDQxNzAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL23Ba49fdxpus3qOXtv8ueCcePbCIEnL/tiTvp+jcTakGilZzJB3M/ktY9hX6RZ4KLcBjM2SClQmNUivEimTBX0U1N8L06GSE8H91tUKup/ofmm6qciU2qiHH4QNHepBADOTbEACoX78O363tUInJlPS1lVlGAGsi5okV+qN7ZLSauh+fKVM07cfw9A6a58es+bFvrojIqS1264GJjns+4baJCVYA4PMPsgxQsWTaOylbnlJC5MYTY2BpBn57dfLO2VtN+lqE5nWkJluAgoX/6OEyxOVchqWFpuyP/p1feQQb8Jc6JFVSs73in95eVFN3Oj5BsvgQdxPwoahZurD1sCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAe5RxtMLU2i4/vN1YacncR3GkOlbRv82rll9cd5mtVmokAw7kwbFBFNo2vIVkun+n+VdJf+QRzmHGm3ABtKwz3DPr78y0qdVFA3h9P60hd3wqu2k5/Q8s9j1Kq3u9TIEoHlGJqNzjqO7khX6VcJ6BRLzoefBYavqoDSgJ3mkkYCNqTV2ZxDNks3obPg4yUkh5flULH14TqlFIOhXbsd775aPuMT+/tyqcc6xohU5NyYA63KtWG1BLDuF4LEF84oNPcY9i0n6IphEGgz20H7YcLRNjU55pDbWGdjE4X8ANb23kAc75RZn9EY4qYCiqeIAg3qEVKLnLUx0fNKMHmuedjg==\"\n" + " ],\n" + " \"x5t\": \"YbRAQRYcE_motWVJKHrwLBbd_9s\"\n" + " },\n" + " {\n" + " \"e\": \"AQAB\",\n" + " \"issuer\": \"https://login.microsoftonline.com/9bc40aaf-e150-4c30-bb3c-a8b3b677266e/v2.0\",\n" + " \"kid\": \"I6oBw4VzBHOqleGrV2AJdA5EmXc\",\n" + " \"kty\": \"RSA\",\n" + " \"n\": \"oRcN8f34zyc04f1l-G4iff5SuR1QE245pzd8eEpWJOm5-qAGXgQbxpw7eIElYweG5f09L_gCCKTbR80b_sGcB2vv_RvRd246HObCtUjB4tDkmS6J-ut1LRwXdaInoT31WybV5hhpNwfjGTkY2Db-wOHNPTfHNeI-FrvgxwtLnRWBuqgEiHawpVwLsTn8YV7kdjAQ10L9R0j7z0fCZJp14U7lDGu5r5ViT1aG0xSQ4SOjyt0FkHTrM5inED9af1LHVFiM6sIEu-Wude-8m0CqWFoKpY5JdP79BZPkB61y8sFKLa3aRanKPz9BzW-ep7Pe99bqoDLNNoDpNtJv7yOXMw\",\n" + " \"use\": \"sig\",\n" + " \"x5c\": [\n" + " \"MIIDBTCCAe2gAwIBAgIQPLxWKJ0EEqNLJ1eIGhsS/jANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE2MDkwNTAwMDAwMFoXDTE4MDkwNjAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKEXDfH9+M8nNOH9ZfhuIn3+UrkdUBNuOac3fHhKViTpufqgBl4EG8acO3iBJWMHhuX9PS/4Agik20fNG/7BnAdr7/0b0XduOhzmwrVIweLQ5JkuifrrdS0cF3WiJ6E99Vsm1eYYaTcH4xk5GNg2/sDhzT03xzXiPha74McLS50VgbqoBIh2sKVcC7E5/GFe5HYwENdC/UdI+89HwmSadeFO5Qxrua+VYk9WhtMUkOEjo8rdBZB06zOYpxA/Wn9Sx1RYjOrCBLvlrnXvvJtAqlhaCqWOSXT+/QWT5AetcvLBSi2t2kWpyj8/Qc1vnqez3vfW6qAyzTaA6TbSb+8jlzMCAwEAAaMhMB8wHQYDVR0OBBYEFJuS8ySZ1mYXPa4Sq1nSrl1G41rXMA0GCSqGSIb3DQEBCwUAA4IBAQBxf5BldsfSq05AAnco9NlToMPsXf46GbInCC/o2R+4WbwJ3uzZe+2/o86nI5gFcq/hGy/HXZXdsWj6py6fI0T5Av0GlhCxAuCmsMoyEMmoGdEnSL6cMfAA57lsAgDGVOB3OdzZoK3um1fpb0paXv1eColOIYsL9lY91Bk4P3E496IDAbkjCjiFzsiQerlmzXSHhvSjvas2g6VTQEwj8/9l4xZO1O3BhExdZHWAkUW1ZciTSB4Ite5bcAHWWBRqMUB7Da5Yj674SocHFhGM+9iM6xaJfMSYjlDFB2rNDSUv8ZLIyDpHB9Ry9N8p7znyixhpiWn0nPVqfX84LMckrgfs\"\n" + " ],\n" + " \"x5t\": \"I6oBw4VzBHOqleGrV2AJdA5EmXc\"\n" + " },\n" + " {\n" + " \"e\": \"AQAB\",\n" + " \"issuer\": \"https://login.microsoftonline.com/9bc40aaf-e150-4c30-bb3c-a8b3b677266e/v2.0\",\n" + " \"kid\": \"RrQqu9rydBVRWmcocuXUb20HGRM\",\n" + " \"kty\": \"RSA\",\n" + " \"n\": \"kqE2PL51yFq3gfJtTHzoUq9sNyIXXLoAu40qihZKzmDkcd0qFJkITQYooSTE6kFJWeE1cN0PAk4lYyZHgFqI03CbM-gXslotiF065TH_xGq-I0mvWRz32l15-DZugtji8T04uLo9jWJE7qem6eE6cSlmpw4gabnIW2Chvi2KWe3ChVhOpiCh2v1wt8TO_QqnVMe6BNo91N8z7RtDEs-XhAWKZ3-y3eK7kGjNz5SPLjQ8ZRsAdSGYQTu_o5ygtjUiy1xqIHJz1F4u8WueQt5n6_DKNVuZw6E-VBWQWiQPAhDom9SVy12Rafc38_Tt2MTTXR0Xn1em6Tn-IWsLNwZc4w\",\n" + " \"use\": \"sig\",\n" + " \"x5c\": [\n" + " \"MIIDBTCCAe2gAwIBAgIQHukklH1Oi5lG9RSJH3l1tDANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE2MTAxNjAwMDAwMFoXDTE4MTAxNzAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJKhNjy+dchat4HybUx86FKvbDciF1y6ALuNKooWSs5g5HHdKhSZCE0GKKEkxOpBSVnhNXDdDwJOJWMmR4BaiNNwmzPoF7JaLYhdOuUx/8RqviNJr1kc99pdefg2boLY4vE9OLi6PY1iRO6npunhOnEpZqcOIGm5yFtgob4tilntwoVYTqYgodr9cLfEzv0Kp1THugTaPdTfM+0bQxLPl4QFimd/st3iu5Bozc+Ujy40PGUbAHUhmEE7v6OcoLY1IstcaiByc9ReLvFrnkLeZ+vwyjVbmcOhPlQVkFokDwIQ6JvUlctdkWn3N/P07djE010dF59Xpuk5/iFrCzcGXOMCAwEAAaMhMB8wHQYDVR0OBBYEFIaXDebTVWUsKdVaPWYQgHO3IhFnMA0GCSqGSIb3DQEBCwUAA4IBAQByhTRtSxoWXZ6iSJgoTt/NdQIuHtgu2HWtd0teIJgBtPGUyLJ+pSXTRUr7hp41WpjcPz6rwq615Xm3pzoGbl+5SK3XlQR0o4/MMa79k+41igmkPhHUBVosaOH1QgpzZATFX12kJxaDOlCjuBLv9gE1y93FbnUkcKItFvbMOXwn38KbzsiYF6cOTtJ4lAfMFoHFkpHWkEkrhhOJMXFpDbMP5ELSOy8usdQJdHHxeHoM28zTaU/SkYZHjqMmrWl6J4fUV7R4aZy7zRZ/NvrPqvhZH2YXGdiEAOvH+VtGDCPOZLjKxJFAgjmpwv4KErKmxCxH8SHp+c0mg3l5QpO0C0v0\"\n" + " ],\n" + " \"x5t\": \"RrQqu9rydBVRWmcocuXUb20HGRM\"\n" + " }\n" + " ]\n" + "}"; }