/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.rs.security.oauth2.utils.crypto; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.lang.annotation.Annotation; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.util.Collections; import java.util.List; import javax.crypto.SecretKey; import javax.ws.rs.core.MediaType; import org.apache.cxf.jaxrs.impl.MetadataMap; import org.apache.cxf.jaxrs.provider.json.JSONProvider; import org.apache.cxf.rs.security.oauth2.common.AccessTokenRegistration; import org.apache.cxf.rs.security.oauth2.common.Client; import org.apache.cxf.rs.security.oauth2.common.OAuthPermission; import org.apache.cxf.rs.security.oauth2.common.ServerAccessToken; import org.apache.cxf.rs.security.oauth2.common.UserSubject; import org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeRegistration; import org.apache.cxf.rs.security.oauth2.grants.code.ServerAuthorizationCodeGrant; import org.apache.cxf.rs.security.oauth2.tokens.bearer.BearerAccessToken; import org.apache.cxf.rs.security.oauth2.tokens.refresh.RefreshToken; import org.apache.cxf.rt.security.crypto.CryptoUtils; import org.apache.cxf.rt.security.crypto.KeyProperties; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class CryptoUtilsTest extends Assert { private CodeGrantEncryptingDataProvider p; @Before public void setUp() throws Exception { p = new CodeGrantEncryptingDataProvider(); } @After public void tearDown() { p = null; } @Test public void testEncryptDecryptToken() throws Exception { AccessTokenRegistration atr = prepareTokenRegistration(); // encrypt ServerAccessToken token = p.createAccessToken(atr); ServerAccessToken token2 = p.getAccessToken(token.getTokenKey()); // compare tokens compareAccessTokens(token, token2); } @Test public void testEncryptDecryptCodeGrant() throws Exception { AuthorizationCodeRegistration codeReg = new AuthorizationCodeRegistration(); codeReg.setAudience("http://bar"); codeReg.setClient(p.getClient("1")); ServerAuthorizationCodeGrant grant = p.createCodeGrant(codeReg); ServerAuthorizationCodeGrant grant2 = p.removeCodeGrant(grant.getCode()); assertEquals("http://bar", grant2.getAudience()); assertEquals("1", grant2.getClient().getClientId()); } @Test public void testBearerTokenCertAndSecretKey() throws Exception { AccessTokenRegistration atr = prepareTokenRegistration(); BearerAccessToken token = p.createAccessTokenInternal(atr); KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); KeyPair keyPair = kpg.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); SecretKey secretKey = CryptoUtils.getSecretKey("AES"); String encryptedSecretKey = CryptoUtils.encryptSecretKey(secretKey, publicKey); String encryptedToken = ModelEncryptionSupport.encryptAccessToken(token, secretKey); token.setTokenKey(encryptedToken); SecretKey decryptedSecretKey = CryptoUtils.decryptSecretKey(encryptedSecretKey, privateKey); ServerAccessToken token2 = ModelEncryptionSupport.decryptAccessToken(p, encryptedToken, decryptedSecretKey); // compare tokens compareAccessTokens(token, token2); } @Test public void testBearerTokenJSON() throws Exception { AccessTokenRegistration atr = prepareTokenRegistration(); BearerAccessToken token = p.createAccessTokenInternal(atr); JSONProvider<BearerAccessToken> jsonp = new JSONProvider<BearerAccessToken>(); jsonp.setMarshallAsJaxbElement(true); jsonp.setUnmarshallAsJaxbElement(true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); jsonp.writeTo(token, BearerAccessToken.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE, new MetadataMap<String, Object>(), bos); String encrypted = CryptoUtils.encryptSequence(bos.toString(), p.key); String decrypted = CryptoUtils.decryptSequence(encrypted, p.key); ServerAccessToken token2 = jsonp.readFrom(BearerAccessToken.class, BearerAccessToken.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE, new MetadataMap<String, String>(), new ByteArrayInputStream(decrypted.getBytes())); // compare tokens compareAccessTokens(token, token2); } @Test public void testBearerTokenJSONCertificate() throws Exception { if ("IBM Corporation".equals(System.getProperty("java.vendor"))) { return; } KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); KeyPair keyPair = kpg.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); AccessTokenRegistration atr = prepareTokenRegistration(); BearerAccessToken token = p.createAccessTokenInternal(atr); JSONProvider<BearerAccessToken> jsonp = new JSONProvider<BearerAccessToken>(); jsonp.setMarshallAsJaxbElement(true); jsonp.setUnmarshallAsJaxbElement(true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); jsonp.writeTo(token, BearerAccessToken.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE, new MetadataMap<String, Object>(), bos); KeyProperties props1 = new KeyProperties(publicKey.getAlgorithm()); String encrypted = CryptoUtils.encryptSequence(bos.toString(), publicKey, props1); KeyProperties props2 = new KeyProperties(privateKey.getAlgorithm()); String decrypted = CryptoUtils.decryptSequence(encrypted, privateKey, props2); ServerAccessToken token2 = jsonp.readFrom(BearerAccessToken.class, BearerAccessToken.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE, new MetadataMap<String, String>(), new ByteArrayInputStream(decrypted.getBytes())); // compare tokens compareAccessTokens(token, token2); } @Test public void testClientJSON() throws Exception { Client c = new Client("client", "secret", true); c.setSubject(new UserSubject("subject", "id")); JSONProvider<Client> jsonp = new JSONProvider<Client>(); jsonp.setMarshallAsJaxbElement(true); jsonp.setUnmarshallAsJaxbElement(true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); jsonp.writeTo(c, Client.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE, new MetadataMap<String, Object>(), bos); String encrypted = CryptoUtils.encryptSequence(bos.toString(), p.key); String decrypted = CryptoUtils.decryptSequence(encrypted, p.key); Client c2 = jsonp.readFrom(Client.class, Client.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE, new MetadataMap<String, String>(), new ByteArrayInputStream(decrypted.getBytes())); assertEquals(c.getClientId(), c2.getClientId()); assertEquals(c.getClientSecret(), c2.getClientSecret()); assertTrue(c2.isConfidential()); assertEquals("subject", c2.getSubject().getLogin()); assertEquals("id", c2.getSubject().getId()); } @Test public void testCodeGrantJSON() throws Exception { Client c = new Client("client", "secret", true); ServerAuthorizationCodeGrant grant = new ServerAuthorizationCodeGrant(c, "code", 1, 2); JSONProvider<ServerAuthorizationCodeGrant> jsonp = new JSONProvider<ServerAuthorizationCodeGrant>(); jsonp.setMarshallAsJaxbElement(true); jsonp.setUnmarshallAsJaxbElement(true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); jsonp.writeTo(grant, ServerAuthorizationCodeGrant.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE, new MetadataMap<String, Object>(), bos); String encrypted = CryptoUtils.encryptSequence(bos.toString(), p.key); String decrypted = CryptoUtils.decryptSequence(encrypted, p.key); ServerAuthorizationCodeGrant grant2 = jsonp.readFrom(ServerAuthorizationCodeGrant.class, Client.class, new Annotation[]{}, MediaType.APPLICATION_JSON_TYPE, new MetadataMap<String, String>(), new ByteArrayInputStream(decrypted.getBytes())); assertEquals("code", grant2.getCode()); assertEquals(1, grant2.getExpiresIn()); assertEquals(2, grant2.getIssuedAt()); } private void compareAccessTokens(ServerAccessToken token, ServerAccessToken token2) { assertEquals(token.getTokenKey(), token2.getTokenKey()); assertEquals(token.getTokenType(), token2.getTokenType()); assertEquals(token.getIssuedAt(), token2.getIssuedAt()); assertEquals(token.getExpiresIn(), token2.getExpiresIn()); Client regClient1 = token.getClient(); Client regClient2 = token2.getClient(); assertEquals(regClient1.getClientId(), regClient2.getClientId()); assertNull(regClient2.getApplicationDescription()); UserSubject endUser1 = token.getSubject(); UserSubject endUser2 = token2.getSubject(); assertEquals(endUser1.getLogin(), endUser2.getLogin()); assertEquals(endUser1.getId(), endUser2.getId()); assertEquals(endUser1.getRoles(), endUser2.getRoles()); assertEquals(token.getRefreshToken(), token2.getRefreshToken()); assertEquals(token.getAudiences(), token2.getAudiences()); assertEquals(token.getGrantType(), token2.getGrantType()); assertEquals(token.getParameters(), token2.getParameters()); List<OAuthPermission> permissions = token.getScopes(); List<OAuthPermission> permissions2 = token2.getScopes(); assertEquals(1, permissions.size()); assertEquals(1, permissions2.size()); OAuthPermission perm1 = permissions.get(0); OAuthPermission perm2 = permissions2.get(0); assertEquals(perm1.getPermission(), perm2.getPermission()); assertEquals(perm1.getDescription(), perm2.getDescription()); RefreshToken refreshToken = ModelEncryptionSupport.decryptRefreshToken(p, token2.getRefreshToken(), p.key); assertEquals(1200L, refreshToken.getExpiresIn()); } private AccessTokenRegistration prepareTokenRegistration() { AccessTokenRegistration atr = new AccessTokenRegistration(); Client regClient = p.getClient("1"); atr.setClient(regClient); atr.setGrantType("code"); atr.setAudiences(Collections.singletonList("http://localhost")); UserSubject endUser = new UserSubject("Barry", "BarryId"); atr.setSubject(endUser); endUser.setRoles(Collections.singletonList("role1")); return atr; } // TODO: remove once the wiki documentation is updated // KeyStore keyStore = loadKeyStore(); // Certificate cert = keyStore.getCertificate("alice"); // PublicKey publicKey = cert.getPublicKey(); // KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) // keyStore.getEntry("alice", new KeyStore.PasswordProtection( // new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'})); // PrivateKey privateKey = pkEntry.getPrivateKey(); // private KeyStore loadKeyStore() throws Exception { // KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); // InputStream is = this.getClass().getResourceAsStream("alice.jks"); // ks.load(is, new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}); // return ks; // } }