diff --git a/pom.xml b/pom.xml index efd235a5f..f17fcf5f3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,162 +1,165 @@ - 4.0.0 - - com.sap.cloud.security.xsuaa - parent - 1.2.0 - pom - - parent - https://github.com/SAP/cloud-security-xsuaa-integration - XSUAA authentication and authorization service integration libraries and samples for authenticating users and services - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - - - - - XSUAA Development - xsuaa-development@sap.com - SAP SE - https://www.sap.com - - - - - scm:git:git://github.com/SAP/cloud-security-xsuaa-integration.git - sscm:git:git://github.com/SAP/cloud-security-xsuaa-integration.git - http://github.com/SAP/cloud-security-xsuaa-integration/tree/master - - - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - - UTF-8 - 5.1.1.RELEASE - 4.12 - 1.8 - 1.8 - 5.1.1.RELEASE - - - - api - spring-xsuaa - spring-xsuaa-it - - - - - - - - - - - default - - true - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.0.1 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.7.0 - - 1.8 - 1.8 - - - - - - - release - - - - - org.apache.maven.plugins - maven-source-plugin - 2.2.1 - - - attach-sources - - jar-no-fork - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.9.1 - - - attach-javadocs - - jar - - - - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.5 - - - sign-artifacts - verify - - sign - - - - - - - org.sonatype.plugins - nexus-staging-maven-plugin - 1.6.7 - true - - ossrh - https://oss.sonatype.org/ - true - - - - - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + com.sap.cloud.security.xsuaa + parent + 1.2.0 + pom + + parent + https://github.com/SAP/cloud-security-xsuaa-integration + XSUAA authentication and authorization service integration libraries and samples for authenticating + users and services + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + + XSUAA Development + xsuaa-development@sap.com + SAP SE + https://www.sap.com + + + + + scm:git:git://github.com/SAP/cloud-security-xsuaa-integration.git + sscm:git:git://github.com/SAP/cloud-security-xsuaa-integration.git + http://github.com/SAP/cloud-security-xsuaa-integration/tree/master + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + UTF-8 + 5.1.1.RELEASE + 4.12 + 1.8 + 1.8 + 5.1.1.RELEASE + + + + api + spring-xsuaa + spring-xsuaa-it + spring-xsuaa-test + + + + + + + + + + + default + + true + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.0.1 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + + + + + + release + + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + attach-sources + + jar-no-fork + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + + + + + diff --git a/spring-xsuaa-test/README.md b/spring-xsuaa-test/README.md new file mode 100644 index 000000000..ca8f0a4eb --- /dev/null +++ b/spring-xsuaa-test/README.md @@ -0,0 +1 @@ +# XSUAA Security Test library \ No newline at end of file diff --git a/spring-xsuaa-test/pom.xml b/spring-xsuaa-test/pom.xml new file mode 100644 index 000000000..244a98f91 --- /dev/null +++ b/spring-xsuaa-test/pom.xml @@ -0,0 +1,142 @@ + + + 4.0.0 + + + com.sap.cloud.security.xsuaa + parent + 1.2.0 + + + spring-xsuaa-test + spring-xsuaa-test + jar + + + + org.springframework.security + spring-security-core + ${spring.core.version} + provided + + + org.springframework.security + spring-security-oauth2-jose + ${spring.security.version} + provided + + + org.springframework.security + spring-security-jwt + 1.0.9.RELEASE + provided + + + commons-io + commons-io + 2.6 + provided + + + junit + junit + ${junit.version} + test + + + org.hamcrest + hamcrest-all + 1.3 + test + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.2 + + + default-prepare-agent + + prepare-agent + + + + default-report + prepare-package + + report + + + + default-check + + check + + + + + + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.10.0 + + + verify + + pmd + cpd + + + + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.5 + + + verify + + findbugs + + + + + + + + diff --git a/spring-xsuaa-test/src/main/java/com/sap/cloud/security/xsuaa/test/JwtGenerator.java b/spring-xsuaa-test/src/main/java/com/sap/cloud/security/xsuaa/test/JwtGenerator.java new file mode 100644 index 000000000..1a6d70283 --- /dev/null +++ b/spring-xsuaa-test/src/main/java/com/sap/cloud/security/xsuaa/test/JwtGenerator.java @@ -0,0 +1,191 @@ +/** + * Copyright (c) 2019 SAP SE or an SAP affiliate company. All rights reserved. + * This file is licensed under the Apache Software License, + * v. 2 except as noted otherwise in the LICENSE file + * https://github.com/SAP/cloud-security-xsuaa-integration/blob/master/LICENSE + */ +package com.sap.cloud.security.xsuaa.test; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.*; + +import org.apache.commons.io.IOUtils; +import org.springframework.security.jwt.JwtHelper; +import org.springframework.security.jwt.crypto.sign.RsaSigner; +import org.springframework.security.oauth2.jwt.Jwt; + +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.JWTParser; + +/** + * Create tokens with a fixed private/public key and dummy values. The client ID, identity zone, and scopes are configurable. + */ +public class JwtGenerator { + + public static final Date NO_EXPIRE_DATE = new Date(Long.MAX_VALUE); + public static final int NO_EXPIRE = Integer.MAX_VALUE; + public static final String CLIENT_ID = "sb-xsapplication!t895"; + public static final String IDENTITY_ZONE_ID = "uaa"; // must be 'uaa' to make use of mockserver (see XsuaaServiceConfigurationDefault.getTokenKeyUrl) + private static final String PRIVATE_KEY_FILE = "/privateKey.txt"; + private final String clientId; + private final String identityZone; + private static final String GRANT_TYPE = "urn:ietf:params:oauth:grant-type:saml2-bearer"; // see TokenImpl.GRANTTYPE_SAML2BEARER; + private String[] scopes; + private String userName = "testuser"; + private String jwtHeaderKeyId; + public Map> attributes = new HashMap<>(); + + /** + * @param clientId + * the client ID that will be used for any created token + */ + public JwtGenerator(String clientId) { + this.clientId = clientId; + this.identityZone = IDENTITY_ZONE_ID; + } + + public JwtGenerator() { + this(CLIENT_ID); + } + + /** + * Changes the value of the jwt claim "user_name". The user name is also used for the "email" claim. + * + * @param userName + * @return + */ + public JwtGenerator setUserName(String userName) { + this.userName = userName; + return this; + } + + /** + * Sets the roles as claim "scope" to the jwt. + * + * @param scopes + * the scopes that should be part of the token + * @return the JwtGenerator itself + */ + public JwtGenerator addScopes(String... scopes) { + this.scopes = scopes; + return this; + } + + /** + * Adds the attributes as claim "xs.user.attribute" to the jwt. + * + * @param attributeName + * the attribute name that should be part of the token + * @param attributeValues + * the attribute value that should be part of the token + * @return the JwtGenerator itself + */ + public JwtGenerator addAttribute(String attributeName, String[] attributeValues) { + List valueList = new ArrayList<>(Arrays.asList(attributeValues)); + attributes.put(attributeName, valueList); + return this; + } + + /** + * Sets the "keyId" value of the jwt token header. + * + * @param keyId + * the value of the signed jwt token header "keyId" + * @return the JwtGenerator itself + */ + public JwtGenerator setJwtHeaderKeyId(String keyId) { + this.jwtHeaderKeyId = keyId; + return this; + } + + /** + * Returns an encoded JWT token for the `Authorization` header + */ + public String getTokenForAuthorizationHeader() { + try { + return "Bearer " + getToken().getTokenValue(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Builds a basic Jwt with the given clientId, userName, scopes and attributes. + * + * @return jwt + */ + public Jwt getToken() throws Exception { + JWTClaimsSet.Builder claimsSetBuilder = getBasicClaimSet(); + + if (scopes != null && scopes.length > 0) { + claimsSetBuilder.claim("scope", scopes); + } + if (attributes.size() > 0) { + claimsSetBuilder.claim("xs.user.attributes", attributes); + } + return createFromClaims(claimsSetBuilder.build()); + } + + public Jwt createFromTemplate(String pathToTemplate) throws Exception { + String claimsFromTemplate = IOUtils.toString(JwtGenerator.class.getResourceAsStream(pathToTemplate), StandardCharsets.UTF_8); + String claimsWithReplacements = replacePlaceholders(claimsFromTemplate); + return createFromClaims(claimsWithReplacements, jwtHeaderKeyId); + } + + public static Jwt createFromFile(String pathToJwt) throws Exception { + return convertTokenToOAuthJwt(IOUtils.resourceToString(pathToJwt, Charset.forName("UTF-8"))); + } + + public static Jwt createFromClaims(JWTClaimsSet claimsSet) throws Exception { + return createFromClaims(claimsSet.toString(), null); + } + + /** + * Builds a basic set of claims + * + * @return a basic set of claims + */ + private JWTClaimsSet.Builder getBasicClaimSet() { + return new JWTClaimsSet.Builder().issueTime(new Date()).expirationTime(JwtGenerator.NO_EXPIRE_DATE).claim("client_id", clientId).claim("origin", "userIdp").claim("cid", clientId).claim("user_name", userName).claim("user_id", "D012345").claim("email", userName + "@test.org").claim("zid", identityZone).claim("grant_type", GRANT_TYPE); + } + + private static Jwt createFromClaims(String claims, String jwtHeaderKeyId) throws Exception { + String token = signAndEncodeToken(claims, jwtHeaderKeyId); + return convertTokenToOAuthJwt(token); + } + + private String replacePlaceholders(String claims) { + claims = claims.replace("$exp", String.valueOf(NO_EXPIRE)); + claims = claims.replace("$clientid", clientId); + claims = claims.replace("$zid", identityZone); + claims = claims.replace("$username", userName); + + return claims; + } + + private static String signAndEncodeToken(String claims, String keyId) throws IOException { + String privateKey = IOUtils.toString(JwtGenerator.class.getResourceAsStream(PRIVATE_KEY_FILE), StandardCharsets.UTF_8); // PEM format + RsaSigner signer = new RsaSigner(privateKey); + + Map headers = Collections.emptyMap(); + if (keyId != null) { + headers = new HashMap<>(); + headers.put("kid", keyId); + } + org.springframework.security.jwt.Jwt jwt = JwtHelper.encode(claims, signer, headers); + + return jwt.getEncoded(); + } + + public static Jwt convertTokenToOAuthJwt(String token) throws java.text.ParseException { + JWT parsedJwt = JWTParser.parse(token); + JWTClaimsSet jwtClaimsSet = parsedJwt.getJWTClaimsSet(); + Map headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject()); + Jwt jwt = new Jwt(parsedJwt.getParsedString(), jwtClaimsSet.getIssueTime().toInstant(), jwtClaimsSet.getExpirationTime().toInstant(), headers, jwtClaimsSet.getClaims()); + return jwt; + } +} diff --git a/spring-xsuaa-test/src/main/resources/privateKey.txt b/spring-xsuaa-test/src/main/resources/privateKey.txt new file mode 100644 index 000000000..2cb9c185b --- /dev/null +++ b/spring-xsuaa-test/src/main/resources/privateKey.txt @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEA2G5MUF7szUMJfiaghYebwB+BgaG4wkbIDZ5fJU8Zm0/Wnaup +CCKX0fguLC21FtHATC6SOpOuVClXe9GY9AVJq3nyqAsiUil66jH9Y+kmeLeRVoBp +8KXMQ15+W69GNU7/sYv+0k5PLUaxJPmcwb+WCq9hw76zRXeEijnZ41YlVC9jcnZ7 +IjHjp2BASoznImmGJDW6F30FRbP/MLtfv5fMpj17OziVNE+eacuIygSH0IZZ+wvV +7AcJAZlEwkCFqzzbVx2cLvRIpacHz2ci4seIIxdPRj8O7i4y29hdSsHqTRFLtQiw +CgIr7YItA5voVY/bS+CYy8a1MSckdXvFa5jYewIDAQABAoIBAQCOCKx6XiFnf2P+ +btkPaHRVPBfge8JldNAa5+Em+ecjHt0Icjwmw5UAza93fLOH+zUIidObL4nLX6oy +7tVC5yl2qDwP/eaTJvesNAxHgh2mQUnXC8T6kcQgPiYMg1U+7M4utWIQoCWj3+2n +B0zRdarA7mHpdP/vScUodVjBsaojuRQSIxWAgOPV72DS07vGDNdOX9MH0PclJRgl +VeZPjbuKKqo0CMthLc6XBJ9A9AsYL4Q3o54F83KgsZoVg6pukYEsJpKY3rqNtzRj +tAVFFLj1Zp9pzHLC2R4yK0ruCOHp3qbcj7y3DX4u6TzfoMPoNCLCG62U8M6ED7v3 +CyzeFoTxAoGBAPvO6rVXAmmTpJ6TdIxcbXZFNETzXQsYbXLZwRjsVOBwzVr1ouiF +3ED/5Bz6Mo9x1d11yDDeetXtC6krHbi0/jFgkg3dsHjlQ54y4ajOwHt4ndJbHuJN +uvgJCbU0mw01K5z/OIwSZviRiSasSAMe/KEywDDp3bwPxa4ZXHFZlvu5AoGBANwI +nr6cnmUXLAwUoBeGtu43QkHaT6kwox2hpfQOfe7DSmYHJs/CF4j6rFTkacahryga +3Ok5/YDDHPsTV8aiHbzW9UZ0ENJ1B0bzuaqSD3Qst9OwD/mVordtDoSCDiBd+Dag +3pdE9FP+NeTIfnBVy1tYjpn8GPy4atlPrm1CN9fTAoGBAKkUyZk2cZI+51zrmmjd +b0rpMS3TU/itUGC8QuLfXibO17VqFxeXOswShzPF9MlJINfxzJiz6ztWTmwrXWu3 +bK/vLmNNJsAnAf5qIAhfu/OsjBzBvr0qgI8oUnJwfmSh/UUQQwIbITVrU/K54Cjo +V65OC6tMfe1Xkd9TfDVIeQ9RAoGBANTQtZFQ9FZ8OgsZK9p1Xps68Se2WlQfCbVQ +Mq3CEoWLd3sFMcHCTXccVO/q2G/Y1AvrJ32grBMNJAunor8o77BFDIhvHBIiRL6Y +XxyeFrpbwhTJ9jmFRBM7NM5u5/DgUoGryH7wn4xZlJDKZpiKMp0QIyTGUvij+hxj +WCau5EonAoGBAIIpqCZMT3FYDUF8lH16fWbOh6hiVZLVo2DrwFN2uHpnVGeDw+VM +I8ZDXvqnZiV+eK0+a8qcQmLoDA3tCKhHQIcZriWwo/S5RGAyBQlnAcR68G//N+Cl +ERTijP+MMgTJuDgMINZCqfUHxlRZij+Vz686T8QDI7w4+AK66Bh8qRLb +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/spring-xsuaa/src/test/resources/publicKey.txt b/spring-xsuaa-test/src/main/resources/publicKey.txt similarity index 100% rename from spring-xsuaa/src/test/resources/publicKey.txt rename to spring-xsuaa-test/src/main/resources/publicKey.txt diff --git a/spring-xsuaa-test/src/test/java/com/sap/cloud/security/xsuaa/test/JwtGeneratorTest.java b/spring-xsuaa-test/src/test/java/com/sap/cloud/security/xsuaa/test/JwtGeneratorTest.java new file mode 100644 index 000000000..c91c8ccb1 --- /dev/null +++ b/spring-xsuaa-test/src/test/java/com/sap/cloud/security/xsuaa/test/JwtGeneratorTest.java @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved. + * This file is licensed under the Apache Software License, + * v. 2 except as noted otherwise in the LICENSE file + * https://github.com/SAP/cloud-security-xsuaa-integration/blob/master/LICENSE + */ +package com.sap.cloud.security.xsuaa.test; + +import static com.sap.cloud.security.xsuaa.test.TestConstants.*; +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.startsWith; + +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.security.oauth2.jwt.Jwt; + +import net.minidev.json.JSONArray; + +public class JwtGeneratorTest { + private JwtGenerator jwtGenerator; + private static final String MY_CLIENT_ID = "client Id"; + private static final String MY_USER_NAME = "UserName"; + + @Before + public void setUp() throws Exception { + jwtGenerator = new JwtGenerator(MY_CLIENT_ID); + } + + @Test + public void testBasicJwtToken() throws Exception { + Jwt jwt = new JwtGenerator().getToken(); + assertThat(jwt.getClaimAsString("zid"), equalTo("uaa")); + assertThat(jwt.getExpiresAt(), not(equals(nullValue()))); + } + + @Test + public void testParameterizedJwtToken() throws Exception { + jwtGenerator.setUserName(MY_USER_NAME); + Jwt jwt = jwtGenerator.getToken(); + assertThat(jwt.getClaimAsString("client_id"), equalTo(MY_CLIENT_ID)); + assertThat(jwt.getClaimAsString("zid"), equalTo(JwtGenerator.IDENTITY_ZONE_ID)); + assertThat(jwt.getClaimAsString("user_name"), equalTo(MY_USER_NAME)); + assertThat(jwt.getClaimAsString("email"), startsWith(MY_USER_NAME)); + assertThat(jwt.getExpiresAt(), not(equals(nullValue()))); + assertThat(jwt.getTokenValue(), not(startsWith("Bearer "))); + } + + @Test + public void testBasicJwtTokenForHeader() throws Exception { + String tokenForHeader = jwtGenerator.getTokenForAuthorizationHeader(); + assertThat(tokenForHeader, startsWith("Bearer ")); + } + + @Test + public void testTokenWithScopes() throws Exception { + Jwt jwt = jwtGenerator.addScopes(new String[] { DUMMY_SCOPE, ANOTHER_SCOPE }).getToken(); + assertThat(jwt.getClaimAsStringList("scope"), hasItems(DUMMY_SCOPE, ANOTHER_SCOPE)); + } + + @Test + public void testTokenWithAttributes() throws Exception { + Jwt jwt = jwtGenerator.addAttribute(DUMMY_ATTRIBUTE, new String[] { DUMMY_ATTRIBUTE }).addAttribute(ANOTHER_ATTRIBUTE, new String[] { ANOTHER_ATTRIBUTE_VALUE, ANOTHER_ATTRIBUTE_VALUE_2 }).getToken(); + Map attributes = jwt.getClaimAsMap("xs.user.attributes"); + assertThat((JSONArray) attributes.get(DUMMY_ATTRIBUTE), contains(DUMMY_ATTRIBUTE)); + assertThat((JSONArray) attributes.get(ANOTHER_ATTRIBUTE), contains(ANOTHER_ATTRIBUTE_VALUE, ANOTHER_ATTRIBUTE_VALUE_2)); + } + + @Test + public void testTokenFromTemplateWithScopesAndAttributes() throws Exception { + jwtGenerator.setUserName(MY_USER_NAME); + Jwt jwt = jwtGenerator.createFromTemplate("/claims_template.txt"); + + assertThat(jwt.getClaimAsString("client_id"), equalTo(MY_CLIENT_ID)); + assertThat(jwt.getClaimAsString("zid"), equalTo(JwtGenerator.IDENTITY_ZONE_ID)); + assertThat(jwt.getClaimAsString("user_name"), equalTo(MY_USER_NAME)); + assertThat(jwt.getClaimAsString("email"), startsWith(MY_USER_NAME)); + + assertThat(jwt.getClaimAsStringList("scope"), hasItems("openid", "testScope", "testApp.localScope")); + + Map attributes = jwt.getClaimAsMap("xs.user.attributes"); + assertThat((JSONArray) attributes.get("usrAttr"), contains("value_1", "value_2")); + jwt.getTokenValue(); + } + + @Test + public void testTokenFromFile() throws Exception { + Jwt jwtFromTemplate = jwtGenerator.createFromTemplate("/claims_template.txt"); + String jwtTokenFromTemplate = jwtFromTemplate.getTokenValue(); + Jwt jwtFromFile = JwtGenerator.createFromFile("/token_cc.txt"); + + assertThat(jwtTokenFromTemplate, equalTo(jwtFromFile.getTokenValue())); + } +} diff --git a/spring-xsuaa-test/src/test/java/com/sap/cloud/security/xsuaa/test/TestConstants.java b/spring-xsuaa-test/src/test/java/com/sap/cloud/security/xsuaa/test/TestConstants.java new file mode 100644 index 000000000..c86e11ea6 --- /dev/null +++ b/spring-xsuaa-test/src/test/java/com/sap/cloud/security/xsuaa/test/TestConstants.java @@ -0,0 +1,10 @@ +package com.sap.cloud.security.xsuaa.test; + +public interface TestConstants { + String DUMMY_SCOPE = "someScope"; + String ANOTHER_SCOPE = "someOtherScope"; + String DUMMY_ATTRIBUTE = "dummy-attribute"; + String ANOTHER_ATTRIBUTE = "another-attribute"; + String ANOTHER_ATTRIBUTE_VALUE = "100"; + String ANOTHER_ATTRIBUTE_VALUE_2 = "200"; +} diff --git a/spring-xsuaa-test/src/test/resources/claims_template.txt b/spring-xsuaa-test/src/test/resources/claims_template.txt new file mode 100644 index 000000000..415f517a9 --- /dev/null +++ b/spring-xsuaa-test/src/test/resources/claims_template.txt @@ -0,0 +1,37 @@ +{ + "jti": "37587e8c45b84a85820744c1459910b5", + "ext_attr": { + "enhancer": "XSUAA", + "serviceinstanceid": "brokerCloneServiceInstanceId", + "zdn": "uaa", + "acl": ["app1!t23"] + }, + "xs.system.attributes": { + "xs.saml.groups": [ + "g1" + ], + "xs.rolecollections": [] + }, + "given_name": "$username", + "xs.user.attributes": {"usrAttr": ["value_1", "value_2"]}, + "family_name": "unknown.org", + "sub": "d21f5de9-d761-47a2-b6d4-2d83161584d9", + "scope": [ + "openid", "testScope", "testApp.localScope" + ], + "client_id": "$clientid", + "cid": "sb-clone1!b5|LR-master!b5", + "azp": "sb-clone1!b5|LR-master!b5", + "grant_type": "urn:ietf:params:oauth:grant-type:saml2-bearer", + "user_id": "d21f5de9-d761-47a2-b6d4-2d83161584d9", + "origin": "useridp", + "user_name": "$username", + "email": "$username@uaa.org", + "rev_sig": "b850756a", + "iat": 1532416849, + "exp": $exp, + "iss": "http://paas.localhost:8080/uaa/oauth/token", + "zid": "$zid", + "aud": [], + "az_attr": {"external_id":"abcd1234"} +} \ No newline at end of file diff --git a/spring-xsuaa-test/src/test/resources/token_cc.txt b/spring-xsuaa-test/src/test/resources/token_cc.txt new file mode 100644 index 000000000..4db4d372e --- /dev/null +++ b/spring-xsuaa-test/src/test/resources/token_cc.txt @@ -0,0 +1 @@ +eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.ewogICJqdGkiOiAiMzc1ODdlOGM0NWI4NGE4NTgyMDc0NGMxNDU5OTEwYjUiLAogICJleHRfYXR0ciI6IHsKICAgICJlbmhhbmNlciI6ICJYU1VBQSIsCiAgICAic2VydmljZWluc3RhbmNlaWQiOiAiYnJva2VyQ2xvbmVTZXJ2aWNlSW5zdGFuY2VJZCIsCiAgICAiemRuIjogInVhYSIsCiAgICAiYWNsIjogWyJhcHAxIXQyMyJdCiAgfSwKICAieHMuc3lzdGVtLmF0dHJpYnV0ZXMiOiB7CiAgICAieHMuc2FtbC5ncm91cHMiOiBbCiAgICAgICJnMSIKICAgIF0sCiAgICAieHMucm9sZWNvbGxlY3Rpb25zIjogW10KICB9LAogICJnaXZlbl9uYW1lIjogInRlc3R1c2VyIiwKICAieHMudXNlci5hdHRyaWJ1dGVzIjogeyJ1c3JBdHRyIjogWyJ2YWx1ZV8xIiwgInZhbHVlXzIiXX0sCiAgImZhbWlseV9uYW1lIjogInVua25vd24ub3JnIiwKICAic3ViIjogImQyMWY1ZGU5LWQ3NjEtNDdhMi1iNmQ0LTJkODMxNjE1ODRkOSIsCiAgInNjb3BlIjogWwogICAgIm9wZW5pZCIsICJ0ZXN0U2NvcGUiLCAidGVzdEFwcC5sb2NhbFNjb3BlIgogIF0sCiAgImNsaWVudF9pZCI6ICJjbGllbnQgSWQiLAogICJjaWQiOiAic2ItY2xvbmUxIWI1fExSLW1hc3RlciFiNSIsCiAgImF6cCI6ICJzYi1jbG9uZTEhYjV8TFItbWFzdGVyIWI1IiwKICAiZ3JhbnRfdHlwZSI6ICJ1cm46aWV0ZjpwYXJhbXM6b2F1dGg6Z3JhbnQtdHlwZTpzYW1sMi1iZWFyZXIiLAogICJ1c2VyX2lkIjogImQyMWY1ZGU5LWQ3NjEtNDdhMi1iNmQ0LTJkODMxNjE1ODRkOSIsCiAgIm9yaWdpbiI6ICJ1c2VyaWRwIiwKICAidXNlcl9uYW1lIjogInRlc3R1c2VyIiwKICAiZW1haWwiOiAidGVzdHVzZXJAdWFhLm9yZyIsCiAgInJldl9zaWciOiAiYjg1MDc1NmEiLAogICJpYXQiOiAxNTMyNDE2ODQ5LAogICJleHAiOiAyMTQ3NDgzNjQ3LAogICJpc3MiOiAiaHR0cDovL3BhYXMubG9jYWxob3N0OjgwODAvdWFhL29hdXRoL3Rva2VuIiwKICAiemlkIjogInVhYSIsCiAgImF1ZCI6IFtdLAogICJhel9hdHRyIjogeyJleHRlcm5hbF9pZCI6ImFiY2QxMjM0In0KfQ.JVHzUhV5Gs1KGu3cG0usSnDYKThN14AiziFgdh1LysQll-AhDSWmf2MFw4J4KKncq_ToW2IbICOtbanzIBqgsoXzAw9GuznXDOJvSjtl6jVTzGjlZBrMnKn3WtWofY6b9PNqfrYoBODGfbY0LE714j83FC_G1fNbEaDD8H26IuzbjrGKpvYOuYXVbFQYEXBFrONJecTNLX0qEBHkyNn_A8lLPizcgsZWI9GEHjMtqnQkOdgQEZMMT2vIenLX6-Xt6yyjdIiNeA1_XWkYqRE8A_3m8qL-AxkHpk0g3z4k4RKRUcwFrVTA1ISQEBeHjm88OJp-tsz27Zx_xJMObJ2IUg \ No newline at end of file diff --git a/spring-xsuaa/pom.xml b/spring-xsuaa/pom.xml index ed549eeb6..c8a83bee3 100644 --- a/spring-xsuaa/pom.xml +++ b/spring-xsuaa/pom.xml @@ -44,19 +44,18 @@ api ${project.version} - com.github.ben-manes.caffeine caffeine ${caffeine.version} + junit junit ${junit.version} test - org.springframework.security spring-security-jwt @@ -75,6 +74,12 @@ 2.23.0 test + + com.sap.cloud.security.xsuaa + spring-xsuaa-test + ${project.version} + test + diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/JwtGenerator.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/JwtGenerator.java deleted file mode 100644 index 57bb4659c..000000000 --- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/JwtGenerator.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.sap.cloud.security.xsuaa.token; - -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - -import org.apache.commons.io.IOUtils; -import org.springframework.security.jwt.JwtHelper; -import org.springframework.security.jwt.crypto.sign.RsaSigner; -import org.springframework.security.oauth2.jwt.Jwt; - -import com.nimbusds.jwt.JWT; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.JWTParser; - -public class JwtGenerator { - public static final Date NO_EXPIRE = new Date(Long.MAX_VALUE); - - public static Jwt createFromTemplate(String pathToTemplate) throws Exception { - String claims = IOUtils.toString(JwtGenerator.class.getResourceAsStream(pathToTemplate), StandardCharsets.UTF_8); - return createFromClaims(claims); - } - - public static Jwt createFromFile(String pathToJwt) throws Exception { - return convertTokenToOAuthJwt(IOUtils.resourceToString(pathToJwt, Charset.forName("UTF-8"))); - } - - public static Jwt createFromClaims(JWTClaimsSet claimsSet) throws Exception { - return createFromClaims(claimsSet.toString()); - } - - private static Jwt createFromClaims(String claims) throws Exception { - String privateKey = IOUtils.toString(JwtGenerator.class.getResourceAsStream("/privateKey.txt"), StandardCharsets.UTF_8); // PEM format - String token = createToken(claims, privateKey, "legacy-samlUserInfo-key"); - return convertTokenToOAuthJwt(token); - } - - private static String createToken(String claims, String privateKey, String keyId) throws Exception { - RsaSigner signer = new RsaSigner(privateKey); - claims = claims.replace("$exp", "" + (System.currentTimeMillis() / 1000 + 500)); - - Map headers = new HashMap<>(); - headers.put("kid", keyId); - - org.springframework.security.jwt.Jwt jwt = JwtHelper.encode(claims, signer, headers); - - return jwt.getEncoded(); - } - - public static Jwt convertTokenToOAuthJwt(String token) throws java.text.ParseException { - JWT parsedJwt = JWTParser.parse(token); - JWTClaimsSet jwtClaimsSet = parsedJwt.getJWTClaimsSet(); - Map headers = new LinkedHashMap<>(parsedJwt.getHeader().toJSONObject()); - Jwt jwt = new Jwt(parsedJwt.getParsedString(), jwtClaimsSet.getIssueTime().toInstant(), jwtClaimsSet.getExpirationTime().toInstant(), headers, jwtClaimsSet.getClaims()); - return jwt; - } -} diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverterTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverterTest.java index 801a59bf3..ac6614d07 100644 --- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverterTest.java +++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenAuthenticationConverterTest.java @@ -10,7 +10,9 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import org.junit.Before; import org.junit.Test; @@ -18,26 +20,22 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.oauth2.jwt.Jwt; -import com.nimbusds.jwt.JWTClaimsSet; +import com.sap.cloud.security.xsuaa.test.JwtGenerator; public class TokenAuthenticationConverterTest { - private JWTClaimsSet.Builder claimsSetBuilder = null; private String xsAppName = "my-app-name!400"; private TokenAuthenticationConverter tokenConverter; String scopeAdmin = xsAppName + "." + "Admin"; String scopeRead = xsAppName + "." + "Read"; - private Jwt jwtSamlWithXsUserAttributes; @Before public void setup() throws Exception { - claimsSetBuilder = new JWTClaimsSet.Builder().issueTime(new Date()).expirationTime(JwtGenerator.NO_EXPIRE); tokenConverter = new TokenAuthenticationConverter(xsAppName); - jwtSamlWithXsUserAttributes = JwtGenerator.createFromTemplate("/saml.txt"); } @Test public void extractAuthoritiesWithoutScopes() throws Exception { - Jwt jwt = JwtGenerator.createFromClaims(claimsSetBuilder.build()); + Jwt jwt = new JwtGenerator().getToken(); AbstractAuthenticationToken authenticationToken = tokenConverter.convert(jwt); assertThat(authenticationToken.getAuthorities().size(), is(0)); @@ -45,11 +43,7 @@ public void extractAuthoritiesWithoutScopes() throws Exception { @Test public void extractAuthoritiesWithScopes() throws Exception { - List scopesList = new ArrayList<>(); - scopesList.add(scopeAdmin); - scopesList.add(scopeRead); - claimsSetBuilder.claim(Token.CLAIM_SCOPES, scopesList); - Jwt jwt = JwtGenerator.createFromClaims(claimsSetBuilder.build()); + Jwt jwt = new JwtGenerator().addScopes(scopeAdmin, scopeRead).getToken(); AbstractAuthenticationToken authenticationToken = tokenConverter.convert(jwt); assertThat(authenticationToken.getAuthorities().size(), is(2)); @@ -61,16 +55,17 @@ public void extractAuthoritiesWithScopes() throws Exception { public void extractCustomAuthoritiesWithScopes() throws Exception { tokenConverter = new MyTokenAuthenticationConverter(xsAppName, "cost-center", "country"); - AbstractAuthenticationToken authenticationToken = tokenConverter.convert(jwtSamlWithXsUserAttributes); - assertThat(authenticationToken.getAuthorities().size(), is(7)); + Jwt jwt = new JwtGenerator().addScopes(scopeAdmin).addAttribute("cost-center", new String[] { "0815" }).addAttribute("country", new String[] { "DE", "IL" }).getToken(); + + AbstractAuthenticationToken authenticationToken = tokenConverter.convert(jwt); + assertThat(authenticationToken.getAuthorities().size(), is(4)); assertThat(authenticationToken.getAuthorities(), hasItem(new SimpleGrantedAuthority("ATTR:COST-CENTER=0815"))); - assertThat(authenticationToken.getAuthorities(), hasItem(new SimpleGrantedAuthority("ATTR:COST-CENTER=4711"))); - assertThat(authenticationToken.getAuthorities(), hasItem(new SimpleGrantedAuthority("ATTR:COUNTRY=Germany"))); - assertThat(authenticationToken.getAuthorities(), hasItem(new SimpleGrantedAuthority("java-hello-world.Delete"))); + assertThat(authenticationToken.getAuthorities(), hasItem(new SimpleGrantedAuthority("ATTR:COUNTRY=DE"))); + assertThat(authenticationToken.getAuthorities(), hasItem(new SimpleGrantedAuthority("ATTR:COUNTRY=IL"))); + assertThat(authenticationToken.getAuthorities(), hasItem(new SimpleGrantedAuthority(scopeAdmin))); } private static class MyTokenAuthenticationConverter extends TokenAuthenticationConverter { - protected String[] xsUserAttributes; public MyTokenAuthenticationConverter(String appId, String... xsUserAttributes) { diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenImplTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenImplTest.java index 9021b727e..fe5966a88 100644 --- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenImplTest.java +++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/TokenImplTest.java @@ -22,6 +22,7 @@ import org.springframework.web.client.RestTemplate; import com.nimbusds.jwt.JWTClaimsSet; +import com.sap.cloud.security.xsuaa.test.JwtGenerator; import com.sap.xs2.security.container.XSTokenRequestImpl; import com.sap.xsa.security.container.XSTokenRequest; @@ -40,17 +41,9 @@ public class TokenImplTest { @Before public void setup() throws Exception { - claimsSetBuilder = new JWTClaimsSet.Builder() - .issueTime(new Date()) - .expirationTime(JwtGenerator.NO_EXPIRE) - .claim(TokenImpl.CLAIM_USER_NAME, userName) - .claim(TokenImpl.CLAIM_EMAIL, userName + "@test.org") - .claim(TokenImpl.CLAIM_ZONE_ID, zoneId) - .claim(TokenImpl.CLAIM_CLIENT_ID, "sb-java-hello-world") - .claim(TokenImpl.CLAIM_ORIGIN, "userIdp") - .claim(TokenImpl.CLAIM_GRANT_TYPE, TokenImpl.GRANTTYPE_SAML2BEARER); - - jwtSaml = JwtGenerator.createFromTemplate("/saml.txt"); + claimsSetBuilder = new JWTClaimsSet.Builder().issueTime(new Date()).expirationTime(JwtGenerator.NO_EXPIRE_DATE).claim(TokenImpl.CLAIM_USER_NAME, userName).claim(TokenImpl.CLAIM_EMAIL, userName + "@test.org").claim(TokenImpl.CLAIM_ZONE_ID, zoneId).claim(TokenImpl.CLAIM_CLIENT_ID, "sb-java-hello-world").claim(TokenImpl.CLAIM_ORIGIN, "userIdp").claim(TokenImpl.CLAIM_GRANT_TYPE, TokenImpl.GRANTTYPE_SAML2BEARER); + + jwtSaml = new JwtGenerator().createFromTemplate("/saml.txt"); jwtCC = JwtGenerator.createFromFile("/token_cc.txt"); jwtCCNoAttributes = JwtGenerator.createFromFile("/token_cc_noattr.txt"); } diff --git a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorTest.java b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorTest.java index 8c9bc5fc8..fd942365f 100644 --- a/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorTest.java +++ b/spring-xsuaa/src/test/java/com/sap/cloud/security/xsuaa/token/authentication/XsuaaAudienceValidatorTest.java @@ -12,7 +12,7 @@ import com.nimbusds.jwt.JWTClaimsSet; import com.sap.cloud.security.xsuaa.XsuaaServiceConfiguration; -import com.sap.cloud.security.xsuaa.token.JwtGenerator; +import com.sap.cloud.security.xsuaa.test.JwtGenerator; import com.sap.cloud.security.xsuaa.token.Token; public class XsuaaAudienceValidatorTest { @@ -30,10 +30,10 @@ public void setup() throws Exception { serviceConfigurationOtherGrantedClientId = new DummyXsuaaServiceConfiguration("sb-test2!t1", "test2!t1"); serviceConfigurationUnGrantedClientId = new DummyXsuaaServiceConfiguration("sb-test3!t1", "test3!t1"); - tokenWithAudience = JwtGenerator.createFromTemplate("/audience_1.txt"); - tokenWithoutAudience = JwtGenerator.createFromTemplate("/audience_2.txt"); + tokenWithAudience = new JwtGenerator().createFromTemplate("/audience_1.txt"); + tokenWithoutAudience = new JwtGenerator().createFromTemplate("/audience_2.txt"); - claimsBuilder = new JWTClaimsSet.Builder().issueTime(new Date()).expirationTime(JwtGenerator.NO_EXPIRE); + claimsBuilder = new JWTClaimsSet.Builder().issueTime(new Date()).expirationTime(JwtGenerator.NO_EXPIRE_DATE); } @Test diff --git a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUtil.java b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUtil.java index 86c5635f2..e6e6a9494 100644 --- a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUtil.java +++ b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/UserInfoTestUtil.java @@ -5,12 +5,12 @@ import org.apache.commons.io.IOUtils; import org.springframework.security.oauth2.jwt.Jwt; -import com.sap.cloud.security.xsuaa.token.JwtGenerator; +import com.sap.cloud.security.xsuaa.test.JwtGenerator; public class UserInfoTestUtil { public static UserInfo createFromTemplate(String pathToTemplate, String appName) throws Exception { - Jwt jwt = JwtGenerator.createFromTemplate(pathToTemplate); + Jwt jwt = new JwtGenerator().createFromTemplate(pathToTemplate); return new UserInfo(jwt, appName); } diff --git a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/XSTokenRequestImplTest.java b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/XSTokenRequestImplTest.java index d1c2fdde9..ea9202d30 100644 --- a/spring-xsuaa/src/test/java/com/sap/xs2/security/container/XSTokenRequestImplTest.java +++ b/spring-xsuaa/src/test/java/com/sap/xs2/security/container/XSTokenRequestImplTest.java @@ -1,10 +1,6 @@ package com.sap.xs2.security.container; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.net.URI; import java.net.URISyntaxException; @@ -30,13 +26,13 @@ public void test_setTokenEndpoint() throws URISyntaxException { request.setTokenEndpoint(tokenEndpoint); assertEquals(request.getTokenEndpoint().toString(), "http://localhost:8080/uaa/oauth/samlUserInfo"); } - - @Test (expected = URISyntaxException.class) + + @Test(expected = URISyntaxException.class) public void test_setTokenEndpoint_fails_UriSyntax() throws URISyntaxException { URI tokenEndpoint = new URI("PC_DEV2::localhost:8080/uaa/oauth/samlUserInfo"); request.setTokenEndpoint(tokenEndpoint); } - + @Test public void test_is_user_token_grant_valid() throws Exception { assertFalse(request.isValid()); @@ -63,7 +59,7 @@ public void test_additional_authorization_attributes() throws Exception { assertEquals("value", request.getAdditionalAuthorizationAttributes().get("key")); assertFalse(request.getAdditionalAuthorizationAttributes().containsKey("hugo")); } - + @Test public void test_additional_authorization_attributes_null() throws Exception { request.setAdditionalAuthorizationAttributes(null); @@ -73,9 +69,8 @@ public void test_additional_authorization_attributes_null() throws Exception { assertNull(request.getAdditionalAuthorizationAttributes().get(null)); assertNotNull(request.getAdditionalAuthorizationAttributes()); /* - assertEquals("bar", request.getAdditionalAuthorizationAttributes().get("foo")); - assertEquals("value", request.getAdditionalAuthorizationAttributes().get("key")); - assertFalse(request.getAdditionalAuthorizationAttributes().containsKey("hugo")); - */ + * assertEquals("bar", request.getAdditionalAuthorizationAttributes().get("foo")); assertEquals("value", + * request.getAdditionalAuthorizationAttributes().get("key")); assertFalse(request.getAdditionalAuthorizationAttributes().containsKey("hugo")); + */ } } diff --git a/spring-xsuaa/src/test/resources/privateKey.txt b/spring-xsuaa/src/test/resources/privateKey.txt deleted file mode 100644 index 2fc7c26c6..000000000 --- a/spring-xsuaa/src/test/resources/privateKey.txt +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAn5dYHyD/nn/Pl+/W8jNGWHDaNItXqPuEk/hiozcPF+9l3qEg -pRZrMx5ya7UjGdvihidGFQ9+efgaaqCLbk+bBsbU5L4WoJK+/t1mgWCiKI0koaAG -DsztZsd3Anz4LEi2+NVNdupRq0ScHzweEKzqaa/LgtBi5WwyA5DaD33gbytG9hdF -JvggzIN9+DSverHSAtqGUHhwHSU4/mL36xSReyqiKDiVyhf/y6V6eiE0USubTEGa -WVUANIteiC+8Ags5UF22QoqMo3ttKnEyFTHpGCXSn+AEO0WMLK1pPavAjPaOyf4c -VX8b/PzHsfBPDMK/kNKNEaU5lAXo8dLUbRYquQIDAQABAoIBAEYNyUDg21RYBmhL -f68Rku9/mkk2YWRsA+ZwQdwjbxyymaUAVbQiAyyNUOy2tpHDU8xPsRPNmVcw8Wec -0Ze6mfJ/lTRTvNr/j5eQ2E4yfPwP+OR5ui8FBbD4HeWZtda6lJbmCvsIIJFtrJqJ -aSkovj1mTY8+qirLM6kdDJuAReSGCUUZGIJPKW65wEBfstZbIRlSulVXCb5SKawh -kvaG0PKp7LtSLelK/32juSaUnyK7amoN7GFTkwQ6o7mWkVYNvbOxk8TQ4E6ATL8z -Um8zqbLrpuSPV7YsIEiM65fbjFz72tRR8ANCyw01jR/LHXLSPLtqFPKOEpJeW/tn -dAVKbYECgYEAzbqcXGWurd6bojD/VFqJ9hd37C2a0uOxB8Wk+xZpflyw8tEuMwYb -UDZlq7MkMNvF1snqGgAW1kpr4FYvGAH/WiSwZynlD8gRgjzcx/VadQ47MeSSHiWD -2Kexej/oU3hmlx1esf6lAwgLXCmU8fVIp/MnBqJWKQuP6xsf85coUxMCgYEAxpaV -IOTQUjNb6Fwjh6MFeqJPWSOQvKSPdUtvr7sYWzi4DYyV1iJOVYWPDZ4lHSn8AR1R -5Cn5EhFMahUB95uItLp9sAAdnHiYqScZz3oOeazk/NmTaeFTlW+Ccjk3AF4+B3ob -P2++WSucnJs4XNNHjRnD3nSxQu6KFPW1BOMKuIMCgYBj/Mp57cGUJ5kknwO5j7d1 -r7pNQ2z4CknEKT8h+aaUD6DAowH9Mn6b4ZRQeuSgCnCBD+mDcX+n7su3YKvK0020 -FhjWSvpVTTuVPNdhJ9IrChujCCAsHreR2Q7dB6p2xxG1aETZ5ZV1f7dlt5/4aOpD -Fl5lTwjpMgFklu5UiabDmQKBgQCFPuI+2OhiTy2awb/hMWPqvd8puzBRMsVC+WOt -8IZOJsdv5+VdcVVIEr5Cb9sNL290O/0Hb5Y8Jjk0cHYKcmSOhxbwMZOsukoMLT0n -NgliYLygX0iG4XZYrSJEi9k4uQM7txVzQgHhCN8jQQ7XUbgPl7sRlxCdDTq/B4H3 -DnPSCwKBgQCc3WbxdpifnZtc6Ve0tywZPQTeceby26WwMK3BrTbtmnp2QjWji/u6 -91PhI0f6z/ICOQWaQ9q3SKhMzMqLM92q4UOlX4TLgnLwZqbrN3E0G6BHz4bv8xRc -h8HblXMLnv2MKGTpArKdx3gtrOHfyxWyLrjwqmxx94Fvnkg+YKNFWA== ------END RSA PRIVATE KEY-----