Return-Path: X-Original-To: apmail-cxf-commits-archive@www.apache.org Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 790F31874E for ; Wed, 20 Jan 2016 16:21:22 +0000 (UTC) Received: (qmail 89799 invoked by uid 500); 20 Jan 2016 16:21:22 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 89674 invoked by uid 500); 20 Jan 2016 16:21:22 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 89134 invoked by uid 99); 20 Jan 2016 16:21:21 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 20 Jan 2016 16:21:21 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 2434DE385D; Wed, 20 Jan 2016 16:21:21 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: coheigea@apache.org To: commits@cxf.apache.org Date: Wed, 20 Jan 2016 16:21:25 -0000 Message-Id: In-Reply-To: <8c9b30bffcde44cf8237d7e002b371f2@git.apache.org> References: <8c9b30bffcde44cf8237d7e002b371f2@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [6/9] cxf git commit: Reshuffle of the tests to share some common code Reshuffle of the tests to share some common code # Conflicts: # systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/OAuthDataProviderImpl.java # Conflicts: # systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/filters/OAuthDataProviderImpl.java # systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantNegativeTest.java # systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java # systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/JAXRSOAuth2Test.java # systests/rs-security/src/test/resources/org/apache/cxf/systest/jaxrs/security/oauth2/server.xml Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/0cc09139 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/0cc09139 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/0cc09139 Branch: refs/heads/3.0.x-fixes Commit: 0cc09139275995f287b013a5c2f856c360425a30 Parents: bd31bc4 Author: Colm O hEigeartaigh Authored: Wed Jan 20 15:00:26 2016 +0000 Committer: Colm O hEigeartaigh Committed: Wed Jan 20 15:37:59 2016 +0000 ---------------------------------------------------------------------- .../jaxrs/security/oauth2/BookServerOAuth2.java | 59 -- .../security/oauth2/CustomGrantHandler.java | 51 -- .../jaxrs/security/oauth2/JAXRSOAuth2Test.java | 374 ------------- .../security/oauth2/SamlCallbackHandler.java | 232 -------- .../security/oauth2/common/BasicAuthFilter.java | 117 ++++ .../oauth2/common/CallbackHandlerImpl.java | 52 ++ .../security/oauth2/common/OAuth2TestUtils.java | 201 +++++++ .../oauth2/common/OAuthDataProviderImpl.java | 164 ++++++ .../oauth2/common/SamlCallbackHandler.java | 231 ++++++++ .../oauth2/filters/OAuth2FiltersTest.java | 169 ++---- .../grants/AuthorizationGrantNegativeTest.java | 268 +++++++-- .../oauth2/grants/AuthorizationGrantTest.java | 107 +++- .../security/oauth2/grants/BasicAuthFilter.java | 117 ---- .../oauth2/grants/BookServerOAuth2.java | 59 ++ .../oauth2/grants/CallbackHandlerImpl.java | 52 -- .../oauth2/grants/CustomGrantHandler.java | 51 ++ .../security/oauth2/grants/JAXRSOAuth2Test.java | 538 +++++++++++++++++++ .../oauth2/grants/OAuthDataProviderImpl.java | 104 ---- .../systest/jaxrs/security/oauth2/client.xml | 38 -- .../security/oauth2/filters/oauth20-server.xml | 6 +- .../oauth2/grants/grants-negative-server.xml | 6 +- .../security/oauth2/grants/grants-server.xml | 6 +- .../jaxrs/security/oauth2/grants/server.xml | 127 +++++ .../systest/jaxrs/security/oauth2/server.xml | 127 +++++ 24 files changed, 2039 insertions(+), 1217 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/BookServerOAuth2.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/BookServerOAuth2.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/BookServerOAuth2.java deleted file mode 100644 index a658e35..0000000 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/BookServerOAuth2.java +++ /dev/null @@ -1,59 +0,0 @@ -/** - * 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.systest.jaxrs.security.oauth2; - -import java.net.URL; - -import org.apache.cxf.Bus; -import org.apache.cxf.BusFactory; -import org.apache.cxf.bus.spring.SpringBusFactory; -import org.apache.cxf.testutil.common.AbstractBusTestServerBase; -import org.apache.cxf.testutil.common.TestUtil; - -public class BookServerOAuth2 extends AbstractBusTestServerBase { - public static final String PORT = TestUtil.getPortNumber("jaxrs-oauth2"); - private static final URL SERVER_CONFIG_FILE = - BookServerOAuth2.class.getResource("server.xml"); - - protected void run() { - SpringBusFactory bf = new SpringBusFactory(); - Bus springBus = bf.createBus(SERVER_CONFIG_FILE); - BusFactory.setDefaultBus(springBus); - setBus(springBus); - - try { - new BookServerOAuth2(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static void main(String[] args) { - try { - BookServerOAuth2 s = new BookServerOAuth2(); - s.start(); - } catch (Exception ex) { - ex.printStackTrace(); - System.exit(-1); - } finally { - System.out.println("done!"); - } - } -} http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/CustomGrantHandler.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/CustomGrantHandler.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/CustomGrantHandler.java deleted file mode 100644 index 1d4b90a..0000000 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/CustomGrantHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * 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.systest.jaxrs.security.oauth2; - -import java.util.Collections; -import java.util.List; - -import javax.ws.rs.core.MultivaluedMap; - -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.ServerAccessToken; -import org.apache.cxf.rs.security.oauth2.provider.AccessTokenGrantHandler; -import org.apache.cxf.rs.security.oauth2.provider.OAuthDataProvider; -import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException; - -public class CustomGrantHandler implements AccessTokenGrantHandler { - - private OAuthDataProvider dataProvider; - - public void setDataProvider(OAuthDataProvider dataProvider) { - this.dataProvider = dataProvider; - } - - public List getSupportedGrantTypes() { - return Collections.singletonList("custom_grant"); - } - - public ServerAccessToken createAccessToken(Client client, MultivaluedMap params) - throws OAuthServiceException { - AccessTokenRegistration atr = new AccessTokenRegistration(); - atr.setClient(client); - return dataProvider.createAccessToken(atr); - } -} http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/JAXRSOAuth2Test.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/JAXRSOAuth2Test.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/JAXRSOAuth2Test.java deleted file mode 100644 index 0452c19..0000000 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/JAXRSOAuth2Test.java +++ /dev/null @@ -1,374 +0,0 @@ -/** - * 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.systest.jaxrs.security.oauth2; - -import java.net.URL; -import java.util.HashMap; -import java.util.Map; - -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; - -import org.apache.cxf.Bus; -import org.apache.cxf.bus.spring.SpringBusFactory; -import org.apache.cxf.common.util.Base64UrlUtility; -import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean; -import org.apache.cxf.jaxrs.client.WebClient; -import org.apache.cxf.jaxrs.impl.MetadataMap; -import org.apache.cxf.rs.security.common.CryptoLoader; -import org.apache.cxf.rs.security.oauth2.auth.saml.Saml2BearerAuthOutInterceptor; -import org.apache.cxf.rs.security.oauth2.client.OAuthClientUtils; -import org.apache.cxf.rs.security.oauth2.common.AccessTokenGrant; -import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; -import org.apache.cxf.rs.security.oauth2.grants.saml.Saml2BearerGrant; -import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException; -import org.apache.cxf.rs.security.oauth2.saml.Constants; -import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants; -import org.apache.cxf.rs.security.saml.SAMLUtils; -import org.apache.cxf.rs.security.saml.SAMLUtils.SelfSignInfo; -import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase; -import org.apache.wss4j.common.crypto.Crypto; -import org.apache.wss4j.common.ext.WSSecurityException; -import org.apache.wss4j.common.saml.SAMLCallback; -import org.apache.wss4j.common.saml.SAMLUtil; -import org.apache.wss4j.common.saml.SamlAssertionWrapper; -import org.apache.wss4j.common.saml.builder.SAML1Constants; -import org.apache.wss4j.common.saml.builder.SAML2Constants; -import org.junit.BeforeClass; -import org.junit.Test; - -public class JAXRSOAuth2Test extends AbstractBusClientServerTestBase { - public static final String PORT = BookServerOAuth2.PORT; - private static final String CRYPTO_RESOURCE_PROPERTIES = - "org/apache/cxf/systest/jaxrs/security/alice.properties"; - - @BeforeClass - public static void startServers() throws Exception { - assertTrue("server did not launch correctly", - launchServer(BookServerOAuth2.class, true)); - } - - @Test - public void testSAML2BearerGrant() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2/token"; - WebClient wc = createWebClient(address); - - Crypto crypto = new CryptoLoader().loadCrypto(CRYPTO_RESOURCE_PROPERTIES); - SelfSignInfo signInfo = new SelfSignInfo(crypto, "alice", "password"); - - String assertion = SAMLUtils.createAssertion(new SamlCallbackHandler(false), - signInfo).assertionToString(); - Saml2BearerGrant grant = new Saml2BearerGrant(assertion); - ClientAccessToken at = OAuthClientUtils.getAccessToken(wc, - new OAuthClientUtils.Consumer("alice", "alice"), - grant, - false); - assertNotNull(at.getTokenKey()); - } - - @Test - public void testSAML2BearerAuthenticationDirect() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2-auth/token"; - WebClient wc = createWebClient(address); - - Crypto crypto = new CryptoLoader().loadCrypto(CRYPTO_RESOURCE_PROPERTIES); - SelfSignInfo signInfo = new SelfSignInfo(crypto, "alice", "password"); - - SamlCallbackHandler samlCallbackHandler = new SamlCallbackHandler(true); - samlCallbackHandler.setIssuer("alice"); - String audienceURI = "https://localhost:" + PORT + "/oauth2-auth/token"; - samlCallbackHandler.setAudience(audienceURI); - - String assertion = SAMLUtils.createAssertion(samlCallbackHandler, - signInfo).assertionToString(); - String encodedAssertion = Base64UrlUtility.encode(assertion); - - Map extraParams = new HashMap(); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_TYPE, Constants.CLIENT_AUTH_SAML2_BEARER); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_PARAM, encodedAssertion); - - ClientAccessToken at = OAuthClientUtils.getAccessToken(wc, - new CustomGrant(), - extraParams); - assertNotNull(at.getTokenKey()); - } - - @Test - public void testTwoWayTLSAuthentication() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2/token"; - WebClient wc = createWebClient(address); - - ClientAccessToken at = OAuthClientUtils.getAccessToken(wc, new CustomGrant()); - assertNotNull(at.getTokenKey()); - } - - @Test - public void testSAML2BearerAuthenticationInterceptor() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2-auth/token"; - WebClient wc = createWebClientWithProps(address); - - ClientAccessToken at = OAuthClientUtils.getAccessToken(wc, - new CustomGrant()); - assertNotNull(at.getTokenKey()); - } - - // - // Some negative tests for authentication - // - - @Test - public void testSAML11() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2-auth/token"; - WebClient wc = createWebClient(address); - - String audienceURI = "https://localhost:" + PORT + "/oauth2-auth/token"; - String assertion = createToken(audienceURI, false, true); - String encodedAssertion = Base64UrlUtility.encode(assertion); - - Map extraParams = new HashMap(); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_TYPE, Constants.CLIENT_AUTH_SAML2_BEARER); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_PARAM, encodedAssertion); - - try { - OAuthClientUtils.getAccessToken(wc, new CustomGrant(), extraParams); - fail("Failure expected on a SAML 1.1 Assertion"); - } catch (OAuthServiceException ex) { - // expected - } - } - - @Test - public void testSAMLAudRestr() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2-auth/token"; - WebClient wc = createWebClient(address); - - String audienceURI = "https://localhost:" + PORT + "/oauth2-auth/token2"; - String assertion = createToken(audienceURI, true, true); - String encodedAssertion = Base64UrlUtility.encode(assertion); - - Map extraParams = new HashMap(); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_TYPE, Constants.CLIENT_AUTH_SAML2_BEARER); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_PARAM, encodedAssertion); - - try { - OAuthClientUtils.getAccessToken(wc, new CustomGrant(), extraParams); - fail("Failure expected on a bad audience restriction"); - } catch (OAuthServiceException ex) { - // expected - } - } - - @Test - public void testSAMLBadSubjectName() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2-auth/token"; - WebClient wc = createWebClient(address); - - String audienceURI = "https://localhost:" + PORT + "/oauth2-auth/token"; - - // Create the SAML Assertion - SamlCallbackHandler samlCallbackHandler = new SamlCallbackHandler(true); - samlCallbackHandler.setSubjectName("bob"); - samlCallbackHandler.setAudience(audienceURI); - - SAMLCallback samlCallback = new SAMLCallback(); - SAMLUtil.doSAMLCallback(samlCallbackHandler, samlCallback); - - SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback); - if (samlCallback.isSignAssertion()) { - samlAssertion.signAssertion( - samlCallback.getIssuerKeyName(), - samlCallback.getIssuerKeyPassword(), - samlCallback.getIssuerCrypto(), - samlCallback.isSendKeyValue(), - samlCallback.getCanonicalizationAlgorithm(), - samlCallback.getSignatureAlgorithm() - ); - } - - String assertion = samlAssertion.assertionToString(); - - String encodedAssertion = Base64UrlUtility.encode(assertion); - - Map extraParams = new HashMap(); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_TYPE, Constants.CLIENT_AUTH_SAML2_BEARER); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_PARAM, encodedAssertion); - - try { - OAuthClientUtils.getAccessToken(wc, new CustomGrant(), extraParams); - fail("Failure expected on a bad subject name"); - } catch (OAuthServiceException ex) { - // expected - } - } - - @Test - public void testSAMLUnsigned() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2-auth/token"; - WebClient wc = createWebClient(address); - - String audienceURI = "https://localhost:" + PORT + "/oauth2-auth/token"; - String assertion = createToken(audienceURI, true, false); - String encodedAssertion = Base64UrlUtility.encode(assertion); - - Map extraParams = new HashMap(); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_TYPE, Constants.CLIENT_AUTH_SAML2_BEARER); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_PARAM, encodedAssertion); - - try { - OAuthClientUtils.getAccessToken(wc, new CustomGrant(), extraParams); - fail("Failure expected on an unsigned token"); - } catch (Exception ex) { - // expected - } - } - - @Test - public void testSAMLHolderOfKey() throws Exception { - String address = "https://localhost:" + PORT + "/oauth2-auth/token"; - WebClient wc = createWebClient(address); - - String audienceURI = "https://localhost:" + PORT + "/oauth2-auth/token"; - - // Create the SAML Assertion - SamlCallbackHandler samlCallbackHandler = new SamlCallbackHandler(true); - samlCallbackHandler.setConfirmationMethod(SAML2Constants.CONF_HOLDER_KEY); - samlCallbackHandler.setSubjectName("alice"); - samlCallbackHandler.setAudience(audienceURI); - - SAMLCallback samlCallback = new SAMLCallback(); - SAMLUtil.doSAMLCallback(samlCallbackHandler, samlCallback); - - SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback); - if (samlCallback.isSignAssertion()) { - samlAssertion.signAssertion( - samlCallback.getIssuerKeyName(), - samlCallback.getIssuerKeyPassword(), - samlCallback.getIssuerCrypto(), - samlCallback.isSendKeyValue(), - samlCallback.getCanonicalizationAlgorithm(), - samlCallback.getSignatureAlgorithm() - ); - } - - String assertion = samlAssertion.assertionToString(); - - String encodedAssertion = Base64UrlUtility.encode(assertion); - - Map extraParams = new HashMap(); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_TYPE, Constants.CLIENT_AUTH_SAML2_BEARER); - extraParams.put(Constants.CLIENT_AUTH_ASSERTION_PARAM, encodedAssertion); - - try { - OAuthClientUtils.getAccessToken(wc, new CustomGrant(), extraParams); - fail("Failure expected on a bad subject confirmation method"); - } catch (OAuthServiceException ex) { - // expected - } - } - - private WebClient createWebClient(String address) { - JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean(); - bean.setAddress(address); - - SpringBusFactory bf = new SpringBusFactory(); - URL busFile = JAXRSOAuth2Test.class.getResource("client.xml"); - Bus springBus = bf.createBus(busFile.toString()); - bean.setBus(springBus); - - WebClient wc = bean.createWebClient(); - wc.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.APPLICATION_JSON); - return wc; - } - - private WebClient createWebClientWithProps(String address) { - JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean(); - bean.setAddress(address); - - SpringBusFactory bf = new SpringBusFactory(); - URL busFile = JAXRSOAuth2Test.class.getResource("client.xml"); - Bus springBus = bf.createBus(busFile.toString()); - bean.setBus(springBus); - - Map properties = new HashMap(); - properties.put("ws-security.callback-handler", - "org.apache.cxf.systest.jaxrs.security.saml.KeystorePasswordCallback"); - - SamlCallbackHandler samlCallbackHandler = new SamlCallbackHandler(true); - samlCallbackHandler.setIssuer("alice"); - String audienceURI = "https://localhost:" + PORT + "/oauth2-auth/token"; - samlCallbackHandler.setAudience(audienceURI); - properties.put("ws-security.saml-callback-handler", samlCallbackHandler); - - properties.put("ws-security.signature.username", "alice"); - properties.put("ws-security.signature.properties", CRYPTO_RESOURCE_PROPERTIES); - bean.setProperties(properties); - - bean.getOutInterceptors().add(new Saml2BearerAuthOutInterceptor()); - - WebClient wc = bean.createWebClient(); - wc.type(MediaType.APPLICATION_FORM_URLENCODED).accept(MediaType.APPLICATION_JSON); - return wc; - } - - private String createToken(String audRestr, boolean saml2, boolean sign) throws WSSecurityException { - SamlCallbackHandler samlCallbackHandler = new SamlCallbackHandler(sign); - samlCallbackHandler.setAudience(audRestr); - if (!saml2) { - samlCallbackHandler.setSaml2(false); - samlCallbackHandler.setConfirmationMethod(SAML1Constants.CONF_BEARER); - } - - SAMLCallback samlCallback = new SAMLCallback(); - SAMLUtil.doSAMLCallback(samlCallbackHandler, samlCallback); - - SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback); - if (samlCallback.isSignAssertion()) { - samlAssertion.signAssertion( - samlCallback.getIssuerKeyName(), - samlCallback.getIssuerKeyPassword(), - samlCallback.getIssuerCrypto(), - samlCallback.isSendKeyValue(), - samlCallback.getCanonicalizationAlgorithm(), - samlCallback.getSignatureAlgorithm() - ); - } - - return samlAssertion.assertionToString(); - } - - private static class CustomGrant implements AccessTokenGrant { - - private static final long serialVersionUID = -4007538779198315873L; - - @Override - public String getType() { - return "custom_grant"; - } - - @Override - public MultivaluedMap toMap() { - MultivaluedMap map = new MetadataMap(); - map.putSingle(OAuthConstants.GRANT_TYPE, "custom_grant"); - return map; - } - - } - -} http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/SamlCallbackHandler.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/SamlCallbackHandler.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/SamlCallbackHandler.java deleted file mode 100644 index 154d31d..0000000 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/SamlCallbackHandler.java +++ /dev/null @@ -1,232 +0,0 @@ -/** - * 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.systest.jaxrs.security.oauth2; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; - -import org.apache.cxf.helpers.CastUtils; -import org.apache.cxf.message.Message; -import org.apache.cxf.phase.PhaseInterceptorChain; -import org.apache.cxf.rt.security.claims.SAMLClaim; -import org.apache.wss4j.common.crypto.Crypto; -import org.apache.wss4j.common.crypto.CryptoFactory; -import org.apache.wss4j.common.ext.WSSecurityException; -import org.apache.wss4j.common.saml.SAMLCallback; -import org.apache.wss4j.common.saml.bean.ActionBean; -import org.apache.wss4j.common.saml.bean.AttributeBean; -import org.apache.wss4j.common.saml.bean.AttributeStatementBean; -import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean; -import org.apache.wss4j.common.saml.bean.AuthDecisionStatementBean; -import org.apache.wss4j.common.saml.bean.AuthDecisionStatementBean.Decision; -import org.apache.wss4j.common.saml.bean.AuthenticationStatementBean; -import org.apache.wss4j.common.saml.bean.ConditionsBean; -import org.apache.wss4j.common.saml.bean.SubjectBean; -import org.apache.wss4j.common.saml.bean.Version; -import org.apache.wss4j.common.saml.builder.SAML2Constants; -import org.joda.time.DateTime; - -/** - * A CallbackHandler instance that is used by the STS to mock up a SAML Attribute Assertion. - */ -public class SamlCallbackHandler implements CallbackHandler { - public static final String PORT = BookServerOAuth2.PORT; - private String confirmationMethod = SAML2Constants.CONF_BEARER; - private boolean signAssertion = true; - private String issuer = "resourceOwner"; - private String audience = "https://localhost:" + PORT + "/oauth2/token"; - private boolean saml2 = true; - private String cryptoPropertiesFile = "org/apache/cxf/systest/jaxrs/security/alice.properties"; - private String issuerKeyName = "alice"; - private String issuerKeyPassword = "password"; - private String subjectName = "alice"; - - public SamlCallbackHandler(boolean signAssertion) { - this.signAssertion = signAssertion; - } - - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { - Message m = PhaseInterceptorChain.getCurrentMessage(); - - for (int i = 0; i < callbacks.length; i++) { - if (callbacks[i] instanceof SAMLCallback) { - SAMLCallback callback = (SAMLCallback) callbacks[i]; - if (saml2) { - callback.setSamlVersion(Version.SAML_20); - } else { - callback.setSamlVersion(Version.SAML_11); - } - callback.setIssuer(issuer); - - String subject = m != null ? (String)m.getContextualProperty("saml.subject.name") : null; - if (subject == null) { - subject = subjectName; - } - String subjectQualifier = "www.mock-sts.com"; - SubjectBean subjectBean = - new SubjectBean( - subject, subjectQualifier, confirmationMethod - ); - callback.setSubject(subjectBean); - - ConditionsBean conditions = new ConditionsBean(); - - AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean(); - audienceRestriction.setAudienceURIs(Collections.singletonList(audience)); - conditions.setAudienceRestrictions(Collections.singletonList(audienceRestriction)); - - callback.setConditions(conditions); - - AuthDecisionStatementBean authDecBean = new AuthDecisionStatementBean(); - authDecBean.setDecision(Decision.INDETERMINATE); - authDecBean.setResource("https://sp.example.com/SAML2"); - authDecBean.setSubject(subjectBean); - - ActionBean actionBean = new ActionBean(); - actionBean.setContents("Read"); - authDecBean.setActions(Collections.singletonList(actionBean)); - callback.setAuthDecisionStatementData(Collections.singletonList(authDecBean)); - - AuthenticationStatementBean authBean = new AuthenticationStatementBean(); - authBean.setSubject(subjectBean); - authBean.setAuthenticationInstant(new DateTime()); - authBean.setSessionIndex("123456"); - authBean.setSubject(subjectBean); - - // AuthnContextClassRef is not set - authBean.setAuthenticationMethod( - "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"); - callback.setAuthenticationStatementData( - Collections.singletonList(authBean)); - - AttributeStatementBean attrBean = new AttributeStatementBean(); - attrBean.setSubject(subjectBean); - - List roles = m != null - ? CastUtils.cast((List)m.getContextualProperty("saml.roles")) : null; - if (roles == null) { - roles = Collections.singletonList("user"); - } - List claims = new ArrayList(); - AttributeBean roleClaim = new AttributeBean(); - roleClaim.setSimpleName("subject-role"); - roleClaim.setQualifiedName(SAMLClaim.SAML_ROLE_ATTRIBUTENAME_DEFAULT); - roleClaim.setNameFormat(SAML2Constants.ATTRNAME_FORMAT_UNSPECIFIED); - roleClaim.setAttributeValues(new ArrayList(roles)); - claims.add(roleClaim); - - List authMethods = - m != null ? CastUtils.cast((List)m.getContextualProperty("saml.auth")) : null; - if (authMethods == null) { - authMethods = Collections.singletonList("password"); - } - - AttributeBean authClaim = new AttributeBean(); - authClaim.setSimpleName("http://claims/authentication"); - authClaim.setQualifiedName("http://claims/authentication"); - authClaim.setNameFormat("http://claims/authentication-format"); - authClaim.setAttributeValues(new ArrayList(authMethods)); - claims.add(authClaim); - - attrBean.setSamlAttributes(claims); - callback.setAttributeStatementData(Collections.singletonList(attrBean)); - - if (signAssertion) { - try { - Crypto crypto = CryptoFactory.getInstance(cryptoPropertiesFile); - callback.setIssuerCrypto(crypto); - callback.setIssuerKeyName(issuerKeyName); - callback.setIssuerKeyPassword(issuerKeyPassword); - callback.setSignAssertion(true); - } catch (WSSecurityException e) { - throw new IOException(e); - } - } - } - } - } - - public String getCryptoPropertiesFile() { - return cryptoPropertiesFile; - } - - public void setCryptoPropertiesFile(String cryptoPropertiesFile) { - this.cryptoPropertiesFile = cryptoPropertiesFile; - } - - public String getIssuerKeyName() { - return issuerKeyName; - } - - public void setIssuerKeyName(String issuerKeyName) { - this.issuerKeyName = issuerKeyName; - } - - public String getIssuerKeyPassword() { - return issuerKeyPassword; - } - - public void setIssuerKeyPassword(String issuerKeyPassword) { - this.issuerKeyPassword = issuerKeyPassword; - } - - public String getIssuer() { - return issuer; - } - - public void setIssuer(String issuer) { - this.issuer = issuer; - } - - public String getAudience() { - return audience; - } - - public void setAudience(String audience) { - this.audience = audience; - } - - public void setConfirmationMethod(String confMethod) { - this.confirmationMethod = confMethod; - } - - public boolean isSaml2() { - return saml2; - } - - public void setSaml2(boolean saml2) { - this.saml2 = saml2; - } - - public String getSubjectName() { - return subjectName; - } - - public void setSubjectName(String subjectName) { - this.subjectName = subjectName; - } - -} http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/BasicAuthFilter.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/BasicAuthFilter.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/BasicAuthFilter.java new file mode 100644 index 0000000..1c74e6e --- /dev/null +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/BasicAuthFilter.java @@ -0,0 +1,117 @@ +/** + * 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.systest.jaxrs.security.oauth2.common; + +import java.io.IOException; +import java.security.Principal; + +import javax.security.auth.callback.CallbackHandler; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.core.Response; + +import org.w3c.dom.Document; + +import org.apache.cxf.configuration.security.AuthorizationPolicy; +import org.apache.cxf.helpers.DOMUtils; +import org.apache.cxf.jaxrs.utils.ExceptionUtils; +import org.apache.cxf.jaxrs.utils.JAXRSUtils; +import org.apache.cxf.message.Message; +import org.apache.cxf.security.SecurityContext; +import org.apache.wss4j.common.principal.WSUsernameTokenPrincipalImpl; +import org.apache.wss4j.dom.WSConstants; +import org.apache.wss4j.dom.handler.RequestData; +import org.apache.wss4j.dom.message.token.UsernameToken; +import org.apache.wss4j.dom.validate.Credential; +import org.apache.wss4j.dom.validate.UsernameTokenValidator; + +/** + * A simple filter to validate a Basic Auth username/password via a CallbackHandler + */ +public class BasicAuthFilter implements ContainerRequestFilter { + + private CallbackHandler callbackHandler; + + public void filter(ContainerRequestContext requestContext) throws IOException { + Message message = JAXRSUtils.getCurrentMessage(); + AuthorizationPolicy policy = message.get(AuthorizationPolicy.class); + + if (policy == null || policy.getUserName() == null || policy.getPassword() == null) { + requestContext.abortWith( + Response.status(401).header("WWW-Authenticate", "Basic realm=\"IdP\"").build()); + } + + try { + UsernameToken token = convertPolicyToToken(policy); + Credential credential = new Credential(); + credential.setUsernametoken(token); + + RequestData data = new RequestData(); + data.setMsgContext(message); + data.setCallbackHandler(callbackHandler); + UsernameTokenValidator validator = new UsernameTokenValidator(); + credential = validator.validate(credential, data); + + // Create a Principal/SecurityContext + Principal p = null; + if (credential != null && credential.getPrincipal() != null) { + p = credential.getPrincipal(); + } else { + p = new WSUsernameTokenPrincipalImpl(policy.getUserName(), false); + ((WSUsernameTokenPrincipalImpl)p).setPassword(policy.getPassword()); + } + message.put(SecurityContext.class, createSecurityContext(p)); + } catch (Exception ex) { + throw ExceptionUtils.toInternalServerErrorException(ex, null); + } + } + + protected UsernameToken convertPolicyToToken(AuthorizationPolicy policy) + throws Exception { + + Document doc = DOMUtils.createDocument(); + UsernameToken token = new UsernameToken(false, doc, + WSConstants.PASSWORD_TEXT); + token.setName(policy.getUserName()); + token.setPassword(policy.getPassword()); + return token; + } + + protected SecurityContext createSecurityContext(final Principal p) { + return new SecurityContext() { + + public Principal getUserPrincipal() { + return p; + } + + public boolean isUserInRole(String arg0) { + return false; + } + }; + } + + public CallbackHandler getCallbackHandler() { + return callbackHandler; + } + + public void setCallbackHandler(CallbackHandler callbackHandler) { + this.callbackHandler = callbackHandler; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/CallbackHandlerImpl.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/CallbackHandlerImpl.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/CallbackHandlerImpl.java new file mode 100644 index 0000000..159740c --- /dev/null +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/CallbackHandlerImpl.java @@ -0,0 +1,52 @@ +/** + * 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.systest.jaxrs.security.oauth2.common; + +import java.io.IOException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.apache.wss4j.common.ext.WSPasswordCallback; + +public class CallbackHandlerImpl implements CallbackHandler { + + public void handle(Callback[] callbacks) throws IOException, + UnsupportedCallbackException { + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof WSPasswordCallback) { // CXF + WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; + if ("alice".equals(pc.getIdentifier())) { + pc.setPassword("security"); + break; + } else if ("bob".equals(pc.getIdentifier())) { + pc.setPassword("security"); + break; + } else if ("consumer-id".equals(pc.getIdentifier())) { + pc.setPassword("this-is-a-secret"); + break; + } else if ("service".equals(pc.getIdentifier())) { + pc.setPassword("service-pass"); + break; + } + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuth2TestUtils.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuth2TestUtils.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuth2TestUtils.java new file mode 100644 index 0000000..8982ee0 --- /dev/null +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuth2TestUtils.java @@ -0,0 +1,201 @@ +/** + * 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.systest.jaxrs.security.oauth2.common; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Properties; + +import javax.ws.rs.core.Form; +import javax.ws.rs.core.Response; + +import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.cxf.jaxrs.provider.json.JSONProvider; +import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm; +import org.apache.cxf.rs.security.jose.jws.JwsHeaders; +import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactProducer; +import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider; +import org.apache.cxf.rs.security.jose.jws.JwsUtils; +import org.apache.cxf.rs.security.jose.jwt.JwtClaims; +import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; +import org.apache.cxf.rs.security.oauth2.common.OAuthAuthorizationData; +import org.apache.cxf.rs.security.oauth2.provider.OAuthJSONProvider; +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.saml.SAMLCallback; +import org.apache.wss4j.common.saml.SAMLUtil; +import org.apache.wss4j.common.saml.SamlAssertionWrapper; +import org.apache.wss4j.common.saml.builder.SAML1Constants; + +/** + * Some test utils for the OAuth 2.0 tests + */ +public final class OAuth2TestUtils { + + private OAuth2TestUtils() { + // complete + } + + public static String getAuthorizationCode(WebClient client) { + return getAuthorizationCode(client, null); + } + + public static String getAuthorizationCode(WebClient client, String scope) { + // Make initial authorization request + client.type("application/json").accept("application/json"); + client.query("client_id", "consumer-id"); + client.query("redirect_uri", "http://www.blah.apache.org"); + client.query("response_type", "code"); + if (scope != null) { + client.query("scope", scope); + } + client.path("authorize/"); + Response response = client.get(); + + OAuthAuthorizationData authzData = response.readEntity(OAuthAuthorizationData.class); + + // Now call "decision" to get the authorization code grant + client.path("decision"); + client.type("application/x-www-form-urlencoded"); + + Form form = new Form(); + form.param("session_authenticity_token", authzData.getAuthenticityToken()); + form.param("client_id", authzData.getClientId()); + form.param("redirect_uri", authzData.getRedirectUri()); + if (authzData.getProposedScope() != null) { + form.param("scope", authzData.getProposedScope()); + } + form.param("oauthDecision", "allow"); + + response = client.post(form); + String location = response.getHeaderString("Location"); + return getSubstring(location, "code"); + } + + public static ClientAccessToken getAccessTokenWithAuthorizationCode(WebClient client, String code) { + client.type("application/x-www-form-urlencoded").accept("application/json"); + client.path("token"); + + Form form = new Form(); + form.param("grant_type", "authorization_code"); + form.param("code", code); + form.param("client_id", "consumer-id"); + Response response = client.post(form); + + return response.readEntity(ClientAccessToken.class); + } + + public static List setupProviders() { + List providers = new ArrayList(); + JSONProvider jsonP = new JSONProvider(); + jsonP.setNamespaceMap(Collections.singletonMap("http://org.apache.cxf.rs.security.oauth", + "ns2")); + providers.add(jsonP); + OAuthJSONProvider oauthProvider = new OAuthJSONProvider(); + providers.add(oauthProvider); + + return providers; + } + + public static String createToken(String audRestr) throws WSSecurityException { + return createToken(audRestr, true, true); + } + + public static String createToken(String audRestr, boolean saml2, boolean sign) + throws WSSecurityException { + SamlCallbackHandler samlCallbackHandler = new SamlCallbackHandler(sign); + samlCallbackHandler.setAudience(audRestr); + if (!saml2) { + samlCallbackHandler.setSaml2(false); + samlCallbackHandler.setConfirmationMethod(SAML1Constants.CONF_BEARER); + } + + SAMLCallback samlCallback = new SAMLCallback(); + SAMLUtil.doSAMLCallback(samlCallbackHandler, samlCallback); + + SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback); + if (samlCallback.isSignAssertion()) { + samlAssertion.signAssertion( + samlCallback.getIssuerKeyName(), + samlCallback.getIssuerKeyPassword(), + samlCallback.getIssuerCrypto(), + samlCallback.isSendKeyValue(), + samlCallback.getCanonicalizationAlgorithm(), + samlCallback.getSignatureAlgorithm() + ); + } + + return samlAssertion.assertionToString(); + } + + public static String createToken(String issuer, String subject, String audience, + boolean expiry, boolean sign) { + // Create the JWT Token + JwtClaims claims = new JwtClaims(); + claims.setSubject(subject); + if (issuer != null) { + claims.setIssuer(issuer); + } + claims.setIssuedAt(new Date().getTime() / 1000L); + if (expiry) { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.SECOND, 60); + claims.setExpiryTime(cal.getTimeInMillis() / 1000L); + } + if (audience != null) { + claims.setAudiences(Collections.singletonList(audience)); + } + + if (sign) { + // Sign the JWT Token + Properties signingProperties = new Properties(); + signingProperties.put("rs.security.keystore.type", "jks"); + signingProperties.put("rs.security.keystore.password", "password"); + signingProperties.put("rs.security.keystore.alias", "alice"); + signingProperties.put("rs.security.keystore.file", + "org/apache/cxf/systest/jaxrs/security/certs/alice.jks"); + signingProperties.put("rs.security.key.password", "password"); + signingProperties.put("rs.security.signature.algorithm", "RS256"); + + JwsHeaders jwsHeaders = new JwsHeaders(signingProperties); + JwsJwtCompactProducer jws = new JwsJwtCompactProducer(jwsHeaders, claims); + + JwsSignatureProvider sigProvider = + JwsUtils.loadSignatureProvider(signingProperties, jwsHeaders); + + return jws.signWith(sigProvider); + } + + JwsHeaders jwsHeaders = new JwsHeaders(SignatureAlgorithm.NONE); + JwsJwtCompactProducer jws = new JwsJwtCompactProducer(jwsHeaders, claims); + return jws.getSignedEncodedJws(); + } + + public static String getSubstring(String parentString, String substringName) { + String foundString = + parentString.substring(parentString.indexOf(substringName + "=") + (substringName + "=").length()); + int ampersandIndex = foundString.indexOf('&'); + if (ampersandIndex < 1) { + ampersandIndex = foundString.length(); + } + return foundString.substring(0, ampersandIndex); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuthDataProviderImpl.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuthDataProviderImpl.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuthDataProviderImpl.java new file mode 100644 index 0000000..0214da9 --- /dev/null +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuthDataProviderImpl.java @@ -0,0 +1,164 @@ +/** + * 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.systest.jaxrs.security.oauth2.common; + +import java.io.InputStream; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.cxf.common.util.Base64Utility; +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.grants.code.DefaultEHCacheCodeDataProvider; +import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException; +import org.apache.cxf.rs.security.oauth2.saml.Constants; +import org.apache.cxf.rt.security.crypto.CryptoUtils; + +/** + * Extend the DefaultEHCacheCodeDataProvider to allow refreshing of tokens + */ +public class OAuthDataProviderImpl extends DefaultEHCacheCodeDataProvider { + + public OAuthDataProviderImpl() throws Exception { + // filters/grants test client + Client client = new Client("consumer-id", "this-is-a-secret", true); + client.setRedirectUris(Collections.singletonList("http://www.blah.apache.org")); + + client.getAllowedGrantTypes().add("authorization_code"); + client.getAllowedGrantTypes().add("refresh_token"); + client.getAllowedGrantTypes().add("implicit"); + client.getAllowedGrantTypes().add("password"); + client.getAllowedGrantTypes().add("client_credentials"); + client.getAllowedGrantTypes().add("urn:ietf:params:oauth:grant-type:saml2-bearer"); + client.getAllowedGrantTypes().add("urn:ietf:params:oauth:grant-type:jwt-bearer"); + + client.getRegisteredScopes().add("read_balance"); + client.getRegisteredScopes().add("create_balance"); + client.getRegisteredScopes().add("read_data"); + client.getRegisteredScopes().add("read_book"); + client.getRegisteredScopes().add("create_book"); + client.getRegisteredScopes().add("create_image"); + + this.setClient(client); + + // JAXRSOAuth2Test clients + client = new Client("alice", "alice", true); + client.getAllowedGrantTypes().add(Constants.SAML2_BEARER_GRANT); + client.getAllowedGrantTypes().add("urn:ietf:params:oauth:grant-type:jwt-bearer"); + client.getAllowedGrantTypes().add("custom_grant"); + this.setClient(client); + + Certificate cert = loadCert(); + String encodedCert = Base64Utility.encode(cert.getEncoded()); + + Client client2 = new Client("CN=whateverhost.com,OU=Morpit,O=ApacheTest,L=Syracuse,C=US", + null, + true, + null, + null); + client2.getAllowedGrantTypes().add("custom_grant"); + client2.setApplicationCertificates(Collections.singletonList(encodedCert)); + this.setClient(client2); + } + + private Certificate loadCert() throws Exception { + InputStream is = this.getClass().getResourceAsStream("/org/apache/cxf/systest/http/resources/Truststore.jks"); + return CryptoUtils.loadCertificate(is, new char[]{'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}, "morpit", null); + } + + @Override + protected boolean isRefreshTokenSupported(List theScopes) { + return true; + } + + @Override + public List convertScopeToPermissions(Client client, List requestedScopes) { + if (requestedScopes.isEmpty()) { + return Collections.emptyList(); + } + + List permissions = new ArrayList(); + for (String requestedScope : requestedScopes) { + if ("read_book".equals(requestedScope)) { + OAuthPermission permission = new OAuthPermission(); + permission.setHttpVerbs(Collections.singletonList("GET")); + List uris = new ArrayList<>(); + String partnerAddress = "/secured/bookstore/books/*"; + uris.add(partnerAddress); + permission.setUris(uris); + + permissions.add(permission); + } else if ("create_book".equals(requestedScope)) { + OAuthPermission permission = new OAuthPermission(); + permission.setHttpVerbs(Collections.singletonList("POST")); + List uris = new ArrayList<>(); + String partnerAddress = "/secured/bookstore/books/*"; + uris.add(partnerAddress); + permission.setUris(uris); + + permissions.add(permission); + } else if ("create_image".equals(requestedScope)) { + OAuthPermission permission = new OAuthPermission(); + permission.setHttpVerbs(Collections.singletonList("POST")); + List uris = new ArrayList<>(); + String partnerAddress = "/secured/bookstore/image/*"; + uris.add(partnerAddress); + permission.setUris(uris); + + permissions.add(permission); + } else if ("read_balance".equals(requestedScope)) { + OAuthPermission permission = new OAuthPermission(); + permission.setPermission("read_balance"); + permission.setHttpVerbs(Collections.singletonList("GET")); + List uris = new ArrayList(); + String partnerAddress = "/partners/balance/*"; + uris.add(partnerAddress); + permission.setUris(uris); + + permissions.add(permission); + } else if ("create_balance".equals(requestedScope)) { + OAuthPermission permission = new OAuthPermission(); + permission.setPermission("create_balance"); + permission.setHttpVerbs(Collections.singletonList("POST")); + List uris = new ArrayList(); + String partnerAddress = "/partners/balance/*"; + uris.add(partnerAddress); + permission.setUris(uris); + + permissions.add(permission); + } else if ("read_data".equals(requestedScope)) { + OAuthPermission permission = new OAuthPermission(); + permission.setPermission("read_data"); + permission.setHttpVerbs(Collections.singletonList("GET")); + List uris = new ArrayList(); + String partnerAddress = "/partners/data/*"; + uris.add(partnerAddress); + permission.setUris(uris); + + permissions.add(permission); + } else { + throw new OAuthServiceException("invalid_scope"); + } + } + + return permissions; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/0cc09139/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/SamlCallbackHandler.java ---------------------------------------------------------------------- diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/SamlCallbackHandler.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/SamlCallbackHandler.java new file mode 100644 index 0000000..d68693e --- /dev/null +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/SamlCallbackHandler.java @@ -0,0 +1,231 @@ +/** + * 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.systest.jaxrs.security.oauth2.common; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.apache.cxf.helpers.CastUtils; +import org.apache.cxf.message.Message; +import org.apache.cxf.phase.PhaseInterceptorChain; +import org.apache.cxf.rt.security.claims.SAMLClaim; +import org.apache.wss4j.common.crypto.Crypto; +import org.apache.wss4j.common.crypto.CryptoFactory; +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.common.saml.SAMLCallback; +import org.apache.wss4j.common.saml.bean.ActionBean; +import org.apache.wss4j.common.saml.bean.AttributeBean; +import org.apache.wss4j.common.saml.bean.AttributeStatementBean; +import org.apache.wss4j.common.saml.bean.AudienceRestrictionBean; +import org.apache.wss4j.common.saml.bean.AuthDecisionStatementBean; +import org.apache.wss4j.common.saml.bean.AuthDecisionStatementBean.Decision; +import org.apache.wss4j.common.saml.bean.AuthenticationStatementBean; +import org.apache.wss4j.common.saml.bean.ConditionsBean; +import org.apache.wss4j.common.saml.bean.SubjectBean; +import org.apache.wss4j.common.saml.bean.Version; +import org.apache.wss4j.common.saml.builder.SAML2Constants; +import org.joda.time.DateTime; + +/** + * A CallbackHandler instance that is used by the STS to mock up a SAML Attribute Assertion. + */ +public class SamlCallbackHandler implements CallbackHandler { + private String confirmationMethod = SAML2Constants.CONF_BEARER; + private boolean signAssertion = true; + private String issuer = "resourceOwner"; + private String audience; + private boolean saml2 = true; + private String cryptoPropertiesFile = "org/apache/cxf/systest/jaxrs/security/alice.properties"; + private String issuerKeyName = "alice"; + private String issuerKeyPassword = "password"; + private String subjectName = "alice"; + + public SamlCallbackHandler(boolean signAssertion) { + this.signAssertion = signAssertion; + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + Message m = PhaseInterceptorChain.getCurrentMessage(); + + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof SAMLCallback) { + SAMLCallback callback = (SAMLCallback) callbacks[i]; + if (saml2) { + callback.setSamlVersion(Version.SAML_20); + } else { + callback.setSamlVersion(Version.SAML_11); + } + callback.setIssuer(issuer); + + String subject = m != null ? (String)m.getContextualProperty("saml.subject.name") : null; + if (subject == null) { + subject = subjectName; + } + String subjectQualifier = "www.mock-sts.com"; + SubjectBean subjectBean = + new SubjectBean( + subject, subjectQualifier, confirmationMethod + ); + callback.setSubject(subjectBean); + + ConditionsBean conditions = new ConditionsBean(); + + AudienceRestrictionBean audienceRestriction = new AudienceRestrictionBean(); + audienceRestriction.setAudienceURIs(Collections.singletonList(audience)); + conditions.setAudienceRestrictions(Collections.singletonList(audienceRestriction)); + + callback.setConditions(conditions); + + AuthDecisionStatementBean authDecBean = new AuthDecisionStatementBean(); + authDecBean.setDecision(Decision.INDETERMINATE); + authDecBean.setResource("https://sp.example.com/SAML2"); + authDecBean.setSubject(subjectBean); + + ActionBean actionBean = new ActionBean(); + actionBean.setContents("Read"); + authDecBean.setActions(Collections.singletonList(actionBean)); + callback.setAuthDecisionStatementData(Collections.singletonList(authDecBean)); + + AuthenticationStatementBean authBean = new AuthenticationStatementBean(); + authBean.setSubject(subjectBean); + authBean.setAuthenticationInstant(new DateTime()); + authBean.setSessionIndex("123456"); + authBean.setSubject(subjectBean); + + // AuthnContextClassRef is not set + authBean.setAuthenticationMethod( + "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"); + callback.setAuthenticationStatementData( + Collections.singletonList(authBean)); + + AttributeStatementBean attrBean = new AttributeStatementBean(); + attrBean.setSubject(subjectBean); + + List roles = m != null + ? CastUtils.cast((List)m.getContextualProperty("saml.roles")) : null; + if (roles == null) { + roles = Collections.singletonList("user"); + } + List claims = new ArrayList(); + AttributeBean roleClaim = new AttributeBean(); + roleClaim.setSimpleName("subject-role"); + roleClaim.setQualifiedName(SAMLClaim.SAML_ROLE_ATTRIBUTENAME_DEFAULT); + roleClaim.setNameFormat(SAML2Constants.ATTRNAME_FORMAT_UNSPECIFIED); + roleClaim.setAttributeValues(new ArrayList(roles)); + claims.add(roleClaim); + + List authMethods = + m != null ? CastUtils.cast((List)m.getContextualProperty("saml.auth")) : null; + if (authMethods == null) { + authMethods = Collections.singletonList("password"); + } + + AttributeBean authClaim = new AttributeBean(); + authClaim.setSimpleName("http://claims/authentication"); + authClaim.setQualifiedName("http://claims/authentication"); + authClaim.setNameFormat("http://claims/authentication-format"); + authClaim.setAttributeValues(new ArrayList(authMethods)); + claims.add(authClaim); + + attrBean.setSamlAttributes(claims); + callback.setAttributeStatementData(Collections.singletonList(attrBean)); + + if (signAssertion) { + try { + Crypto crypto = CryptoFactory.getInstance(cryptoPropertiesFile); + callback.setIssuerCrypto(crypto); + callback.setIssuerKeyName(issuerKeyName); + callback.setIssuerKeyPassword(issuerKeyPassword); + callback.setSignAssertion(true); + } catch (WSSecurityException e) { + throw new IOException(e); + } + } + } + } + } + + public String getCryptoPropertiesFile() { + return cryptoPropertiesFile; + } + + public void setCryptoPropertiesFile(String cryptoPropertiesFile) { + this.cryptoPropertiesFile = cryptoPropertiesFile; + } + + public String getIssuerKeyName() { + return issuerKeyName; + } + + public void setIssuerKeyName(String issuerKeyName) { + this.issuerKeyName = issuerKeyName; + } + + public String getIssuerKeyPassword() { + return issuerKeyPassword; + } + + public void setIssuerKeyPassword(String issuerKeyPassword) { + this.issuerKeyPassword = issuerKeyPassword; + } + + public String getIssuer() { + return issuer; + } + + public void setIssuer(String issuer) { + this.issuer = issuer; + } + + public String getAudience() { + return audience; + } + + public void setAudience(String audience) { + this.audience = audience; + } + + public void setConfirmationMethod(String confMethod) { + this.confirmationMethod = confMethod; + } + + public boolean isSaml2() { + return saml2; + } + + public void setSaml2(boolean saml2) { + this.saml2 = saml2; + } + + public String getSubjectName() { + return subjectName; + } + + public void setSubjectName(String subjectName) { + this.subjectName = subjectName; + } + +}