You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2013/02/21 16:57:25 UTC
svn commit: r1448696 [1/2] - in /cxf/trunk:
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/
rt/rs/security/oauth-parent/ rt/rs/security/oauth-parent/oauth2-saml/
rt/rs/security/...
Author: sergeyb
Date: Thu Feb 21 15:57:24 2013
New Revision: 1448696
URL: http://svn.apache.org/r1448696
Log:
[CXF-4828] Support for OAuth2 SAML2 grants and authentication
Added:
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/pom.xml (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthHandler.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthOutInterceptor.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrant.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrantHandler.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/SamlUserSubject.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Base64UrlUtility.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Constants.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/SamlOAuthValidator.java (with props)
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/org/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/org/apache/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/org/apache/cxf/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/org/apache/cxf/rs/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/org/apache/cxf/rs/security/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/org/apache/cxf/rs/security/oauth2/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/org/apache/cxf/rs/security/oauth2/grants/
cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/test/java/org/apache/cxf/rs/security/oauth2/grants/saml/
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/BookServerOAuth2.java (with props)
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/CustomGrantHandler.java (with props)
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/JAXRSOAuth2Test.java (with props)
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/OAuthDataProviderImpl.java (with props)
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/SamlCallbackHandler.java (with props)
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/SamlCallbackHandler2.java (with props)
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/client.xml (with props)
cxf/trunk/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/server.xml (with props)
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/OAuthClientUtils.java
cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/owner/ResourceOwnerGrant.java
cxf/trunk/rt/rs/security/oauth-parent/pom.xml
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/CryptoLoader.java
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormInHandler.java
cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormOutInterceptor.java
cxf/trunk/systests/rs-security/pom.xml
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java Thu Feb 21 15:57:24 2013
@@ -63,6 +63,14 @@ public class FormEncodingProvider<T> imp
private boolean expectEncoded;
+ public FormEncodingProvider() {
+
+ }
+
+ public FormEncodingProvider(boolean expectEncoded) {
+ this.expectEncoded = expectEncoded;
+ }
+
public void setExpectedEncoded(boolean expect) {
this.expectEncoded = expect;
}
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java Thu Feb 21 15:57:24 2013
@@ -23,6 +23,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
@@ -34,15 +35,20 @@ import javax.servlet.http.HttpServletReq
import javax.ws.rs.BadRequestException;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.interceptor.LoggingInInterceptor;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.jaxrs.ext.form.Form;
import org.apache.cxf.jaxrs.ext.multipart.Attachment;
import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
+import org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.jaxrs.provider.FormEncodingProvider;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.PhaseInterceptorChain;
@@ -57,6 +63,30 @@ public final class FormUtils {
}
+ public static void restoreForm(FormEncodingProvider<Form> provider,
+ Form form,
+ Message message)
+ throws Exception {
+ CachedOutputStream os = new CachedOutputStream();
+ writeForm(provider, form, os);
+ message.setContent(InputStream.class, os.getInputStream());
+ }
+
+ public static void writeForm(FormEncodingProvider<Form> provider,
+ Form form, OutputStream os)
+ throws Exception {
+ provider.writeTo(form, Form.class, Form.class, new Annotation[]{},
+ MediaType.APPLICATION_FORM_URLENCODED_TYPE, new MetadataMap<String, Object>(), os);
+ }
+
+ public static Form readForm(FormEncodingProvider<Form> provider, Message message)
+ throws Exception {
+ return provider.readFrom(Form.class, Form.class,
+ new Annotation[]{}, MediaType.APPLICATION_FORM_URLENCODED_TYPE,
+ new MetadataMap<String, String>(),
+ message.getContent(InputStream.class));
+ }
+
public static void addPropertyToForm(MultivaluedMap<String, String> map, String name, Object value) {
if (!"".equals(name)) {
map.add(name, value.toString());
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/pom.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/pom.xml?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/pom.xml (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/pom.xml Thu Feb 21 15:57:24 2013
@@ -0,0 +1,62 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-security-oauth2-saml</artifactId>
+ <version>2.8.0-SNAPSHOT</version>
+
+ <packaging>jar</packaging>
+ <name>Apache CXF Runtime OAuth 2.0 SAML</name>
+ <description>Apache CXF Runtime OAuth 2.0 SAML</description>
+ <url>http://cxf.apache.org</url>
+
+ <parent>
+ <artifactId>cxf-rt-rs-security-oauth-parent</artifactId>
+ <groupId>org.apache.cxf</groupId>
+ <version>2.8.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-security-oauth2</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-security-xml</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!--test dependencies-->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/pom.xml
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/pom.xml
------------------------------------------------------------------------------
svn:keywords = Rev Date
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/pom.xml
------------------------------------------------------------------------------
svn:mime-type = text/xml
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthHandler.java?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthHandler.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthHandler.java Thu Feb 21 15:57:24 2013
@@ -0,0 +1,131 @@
+/**
+ * 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.auth.saml;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.core.Response;
+
+import org.w3c.dom.Element;
+
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.jaxrs.ext.form.Form;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.provider.FormEncodingProvider;
+import org.apache.cxf.jaxrs.utils.FormUtils;
+import org.apache.cxf.jaxrs.utils.HttpUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.rs.security.oauth2.saml.Base64UrlUtility;
+import org.apache.cxf.rs.security.oauth2.saml.Constants;
+import org.apache.cxf.rs.security.oauth2.saml.SamlOAuthValidator;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
+import org.apache.cxf.rs.security.saml.AbstractSamlInHandler;
+import org.apache.cxf.rs.security.saml.SAMLUtils;
+import org.apache.cxf.rs.security.saml.assertion.Subject;
+import org.apache.ws.security.saml.ext.AssertionWrapper;
+
+public class Saml2BearerAuthHandler extends AbstractSamlInHandler {
+ private FormEncodingProvider<Form> provider = new FormEncodingProvider<Form>(true);
+ private SamlOAuthValidator samlOAuthValidator = new SamlOAuthValidator();
+
+ public Saml2BearerAuthHandler() {
+ }
+
+ public void setSamlOAuthValidator(SamlOAuthValidator validator) {
+ samlOAuthValidator = validator;
+ }
+
+ public Response handleRequest(Message message, ClassResourceInfo resourceClass) {
+
+ Form form = readFormData(message);
+ String assertionType = form.getData().getFirst(Constants.CLIENT_AUTH_ASSERTION_TYPE);
+ String decodedAssertionType = assertionType != null ? HttpUtils.urlDecode(assertionType) : null;
+ if (decodedAssertionType == null || !Constants.CLIENT_AUTH_SAML2_BEARER.equals(decodedAssertionType)) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+ String assertion = form.getData().getFirst(Constants.CLIENT_AUTH_ASSERTION_PARAM);
+
+ Element token = readToken(message, assertion);
+ String clientId = form.getData().getFirst(OAuthConstants.CLIENT_ID);
+ validateToken(message, token, clientId);
+
+
+ form.getData().remove(OAuthConstants.CLIENT_ID);
+ form.getData().remove(Constants.CLIENT_AUTH_ASSERTION_PARAM);
+ form.getData().remove(Constants.CLIENT_AUTH_ASSERTION_TYPE);
+
+ // restore input stream
+ try {
+ FormUtils.restoreForm(provider, form, message);
+ } catch (Exception ex) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+ return null;
+ }
+
+ private Form readFormData(Message message) {
+ try {
+ return FormUtils.readForm(provider, message);
+ } catch (Exception ex) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+ }
+
+ protected Element readToken(Message message, String assertion) {
+ if (assertion == null) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+ try {
+ byte[] deflatedToken = Base64UrlUtility.decode(assertion);
+ InputStream is = new ByteArrayInputStream(deflatedToken);
+ return readToken(message, is);
+ } catch (Base64Exception ex) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+ }
+
+ protected void validateToken(Message message, Element element, String clientId) {
+
+ AssertionWrapper wrapper = toWrapper(element);
+ // The common SAML assertion validation:
+ // signature, subject confirmation, etc
+ super.validateToken(message, wrapper);
+
+ // This is specific to OAuth2 path
+ // Introduce SAMLOAuth2Validator to be reused between auth and grant handlers
+ Subject subject = SAMLUtils.getSubject(message, wrapper);
+ if (subject.getName() == null) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+
+ if (clientId != null && !clientId.equals(subject.getName())) {
+ //TODO: Attempt to map client_id to subject.getName()
+ throw new NotAuthorizedException(errorResponse());
+ }
+ samlOAuthValidator.validate(message, wrapper);
+ message.put(OAuthConstants.CLIENT_ID, subject.getName());
+ }
+
+ private static Response errorResponse() {
+ return Response.status(401).build();
+ }
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthHandler.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthOutInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthOutInterceptor.java?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthOutInterceptor.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthOutInterceptor.java Thu Feb 21 15:57:24 2013
@@ -0,0 +1,39 @@
+/**
+ * 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.auth.saml;
+
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.jaxrs.ext.form.Form;
+import org.apache.cxf.rs.security.oauth2.saml.Base64UrlUtility;
+import org.apache.cxf.rs.security.oauth2.saml.Constants;
+import org.apache.cxf.rs.security.saml.SamlFormOutInterceptor;
+
+public class Saml2BearerAuthOutInterceptor extends SamlFormOutInterceptor {
+
+ @Override
+ protected void updateForm(Form form, String encodedToken) {
+ form.set(Constants.CLIENT_AUTH_ASSERTION_TYPE, Constants.CLIENT_AUTH_SAML2_BEARER);
+ form.set(Constants.CLIENT_AUTH_ASSERTION_PARAM, encodedToken);
+ }
+
+ @Override
+ protected String encodeToken(String token) throws Base64Exception {
+ return Base64UrlUtility.encode(token);
+ }
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthOutInterceptor.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/auth/saml/Saml2BearerAuthOutInterceptor.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrant.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrant.java?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrant.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrant.java Thu Feb 21 15:57:24 2013
@@ -0,0 +1,78 @@
+/**
+ * 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.grants.saml;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.cxf.jaxrs.impl.MetadataMap;
+import org.apache.cxf.rs.security.oauth2.common.AccessTokenGrant;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+import org.apache.cxf.rs.security.oauth2.saml.Base64UrlUtility;
+import org.apache.cxf.rs.security.oauth2.saml.Constants;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
+
+public class Saml2BearerGrant implements AccessTokenGrant {
+ private String assertion;
+ private String scope;
+ private boolean encoded;
+
+ public Saml2BearerGrant(String assertion) {
+ this(assertion, false);
+ }
+
+ public Saml2BearerGrant(String assertion, boolean encoded) {
+ this(assertion, false, null);
+ }
+
+ public Saml2BearerGrant(String assertion, String scope) {
+ this(assertion, false, scope);
+ }
+
+ public Saml2BearerGrant(String assertion, boolean encoded, String scope) {
+ this.assertion = assertion;
+ this.encoded = encoded;
+ this.scope = scope;
+ }
+
+ public String getType() {
+ return Constants.SAML2_BEARER_GRANT;
+ }
+
+ public MultivaluedMap<String, String> toMap() {
+ MultivaluedMap<String, String> map = new MetadataMap<String, String>();
+ map.putSingle(OAuthConstants.GRANT_TYPE, Constants.SAML2_BEARER_GRANT);
+ map.putSingle(Constants.CLIENT_GRANT_ASSERTION_PARAM, encodeAssertion());
+ if (scope != null) {
+ map.putSingle(OAuthConstants.SCOPE, scope);
+ }
+ return map;
+ }
+
+ protected String encodeAssertion() {
+ if (encoded) {
+ return assertion;
+ }
+
+ try {
+ return Base64UrlUtility.encode(assertion);
+ } catch (Exception ex) {
+ throw new OAuthServiceException(ex.getMessage(), ex);
+ }
+ }
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrant.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrant.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrantHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrantHandler.java?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrantHandler.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrantHandler.java Thu Feb 21 15:57:24 2013
@@ -0,0 +1,220 @@
+/**
+ * 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.grants.saml;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.helpers.DOMUtils;
+import org.apache.cxf.jaxrs.utils.HttpUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.apache.cxf.rs.security.common.CryptoLoader;
+import org.apache.cxf.rs.security.common.SecurityUtils;
+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.common.UserSubject;
+import org.apache.cxf.rs.security.oauth2.grants.AbstractGrantHandler;
+import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException;
+import org.apache.cxf.rs.security.oauth2.saml.Base64UrlUtility;
+import org.apache.cxf.rs.security.oauth2.saml.Constants;
+import org.apache.cxf.rs.security.oauth2.saml.SamlOAuthValidator;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils;
+import org.apache.cxf.rs.security.saml.authorization.JAXRSSAMLSecurityContext;
+import org.apache.cxf.rs.security.saml.authorization.SecurityContextProvider;
+import org.apache.cxf.rs.security.saml.authorization.SecurityContextProviderImpl;
+import org.apache.cxf.security.SecurityContext;
+import org.apache.cxf.security.transport.TLSSessionInfo;
+import org.apache.cxf.ws.security.SecurityConstants;
+import org.apache.ws.security.WSSConfig;
+import org.apache.ws.security.handler.RequestData;
+import org.apache.ws.security.handler.WSHandlerConstants;
+import org.apache.ws.security.saml.ext.AssertionWrapper;
+import org.apache.ws.security.validate.Credential;
+import org.apache.ws.security.validate.SamlAssertionValidator;
+import org.apache.ws.security.validate.Validator;
+
+/**
+ * The "SAML2 Bearer" grant handler
+ */
+public class Saml2BearerGrantHandler extends AbstractGrantHandler {
+ private static final String ENCODED_SAML2_BEARER_GRANT;
+ static {
+ WSSConfig.init();
+ ENCODED_SAML2_BEARER_GRANT = HttpUtils.urlEncode(Constants.SAML2_BEARER_GRANT, "UTF-8");
+ }
+ private Validator samlValidator = new SamlAssertionValidator();
+ private SamlOAuthValidator samlOAuthValidator = new SamlOAuthValidator();
+ private SecurityContextProvider scProvider = new SecurityContextProviderImpl();
+
+ public Saml2BearerGrantHandler() {
+ super(Constants.SAML2_BEARER_GRANT, true);
+ }
+
+ @Override
+ public List<String> getSupportedGrantTypes() {
+ // AccessTokenService may be configured with the form provider
+ // which will not decode by default - so listing both the actual
+ // and encoded grant type value will help
+ List<String> types = new LinkedList<String>();
+ types.add(Constants.SAML2_BEARER_GRANT);
+ types.add(ENCODED_SAML2_BEARER_GRANT);
+ return types;
+ }
+
+ public void setSamlValidator(Validator validator) {
+ samlValidator = validator;
+ }
+
+ public void setSamlOAuthValidator(SamlOAuthValidator validator) {
+ samlOAuthValidator = validator;
+ }
+
+ public void setSecurityContextProvider(SecurityContextProvider p) {
+ scProvider = p;
+ }
+
+ public ServerAccessToken createAccessToken(Client client, MultivaluedMap<String, String> params)
+ throws OAuthServiceException {
+ checkIfGrantSupported(client);
+
+ String assertion = params.getFirst(Constants.CLIENT_GRANT_ASSERTION_PARAM);
+ if (assertion == null) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT);
+ }
+ try {
+ InputStream tokenStream = decodeAssertion(assertion);
+ Element token = readToken(tokenStream);
+ AssertionWrapper assertionWrapper = new AssertionWrapper(token);
+
+ Message message = PhaseInterceptorChain.getCurrentMessage();
+
+ validateToken(message, assertionWrapper);
+ UserSubject grantSubject = getGrantSubject(message, assertionWrapper);
+
+ return doCreateAccessToken(client,
+ grantSubject,
+ OAuthUtils.parseScope(params.getFirst(OAuthConstants.SCOPE)));
+ } catch (OAuthServiceException ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT, ex);
+ }
+ }
+
+ protected UserSubject getGrantSubject(Message message, AssertionWrapper wrapper) {
+ SecurityContext sc = scProvider.getSecurityContext(message, wrapper);
+ if (sc instanceof JAXRSSAMLSecurityContext) {
+ JAXRSSAMLSecurityContext jaxrsSc = (JAXRSSAMLSecurityContext)sc;
+ Set<Principal> rolesP = jaxrsSc.getUserRoles();
+ List<String> roles = new ArrayList<String>();
+ if (roles != null) {
+ for (Principal p : rolesP) {
+ roles.add(p.getName());
+ }
+ }
+ return new SamlUserSubject(jaxrsSc.getUserPrincipal().getName(),
+ roles,
+ jaxrsSc.getClaims());
+ } else {
+ return new UserSubject(sc.getUserPrincipal().getName());
+ }
+
+ }
+
+ private InputStream decodeAssertion(String assertion) {
+ try {
+ byte[] deflatedToken = Base64UrlUtility.decode(assertion);
+ return new ByteArrayInputStream(deflatedToken);
+ } catch (Base64Exception ex) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT);
+ }
+ }
+
+
+ protected Element readToken(InputStream tokenStream) {
+
+ try {
+ Document doc = DOMUtils.readXml(new InputStreamReader(tokenStream, "UTF-8"));
+ return doc.getDocumentElement();
+ } catch (Exception ex) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT);
+ }
+ }
+
+ protected void validateToken(Message message, AssertionWrapper assertion) {
+ try {
+ RequestData data = new RequestData();
+ if (assertion.isSigned()) {
+ WSSConfig cfg = WSSConfig.getNewInstance();
+ data.setWssConfig(cfg);
+ data.setCallbackHandler(SecurityUtils.getCallbackHandler(message, this.getClass()));
+ try {
+ data.setSigCrypto(new CryptoLoader().getCrypto(message,
+ SecurityConstants.SIGNATURE_CRYPTO,
+ SecurityConstants.SIGNATURE_PROPERTIES));
+ } catch (IOException ex) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT);
+ }
+ data.setEnableRevocation(MessageUtils.isTrue(
+ message.getContextualProperty(WSHandlerConstants.ENABLE_REVOCATION)));
+ assertion.verifySignature(data, null);
+ } else if (getTLSCertificates(message) == null) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT);
+ }
+
+ if (samlValidator != null) {
+ Credential credential = new Credential();
+ credential.setAssertion(assertion);
+ samlValidator.validate(credential, data);
+ }
+ samlOAuthValidator.validate(message, assertion);
+ } catch (Exception ex) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT, ex);
+ }
+ }
+
+ private Certificate[] getTLSCertificates(Message message) {
+ TLSSessionInfo tlsInfo = message.get(TLSSessionInfo.class);
+ return tlsInfo != null ? tlsInfo.getPeerCertificates() : null;
+ }
+
+ protected void setSecurityContext(Message message, AssertionWrapper wrapper) {
+ if (scProvider != null) {
+ SecurityContext sc = scProvider.getSecurityContext(message, wrapper);
+ message.put(SecurityContext.class, sc);
+ }
+ }
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrantHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/Saml2BearerGrantHandler.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/SamlUserSubject.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/SamlUserSubject.java?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/SamlUserSubject.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/SamlUserSubject.java Thu Feb 21 15:57:24 2013
@@ -0,0 +1,37 @@
+/**
+ * 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.grants.saml;
+
+import java.util.List;
+
+import org.apache.cxf.rs.security.oauth2.common.UserSubject;
+import org.apache.cxf.rs.security.saml.assertion.Claims;
+
+public class SamlUserSubject extends UserSubject {
+ private Claims claims;
+ public SamlUserSubject(String user,
+ List<String> roles,
+ Claims claims) {
+ super(user, roles);
+ this.claims = claims;
+ }
+ public Claims getClaims() {
+ return claims;
+ }
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/SamlUserSubject.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/grants/saml/SamlUserSubject.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Base64UrlUtility.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Base64UrlUtility.java?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Base64UrlUtility.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Base64UrlUtility.java Thu Feb 21 15:57:24 2013
@@ -0,0 +1,380 @@
+/**
+ * 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.saml;
+
+/**
+ * Base64 URL Encoding/Decoding utility (character 62 is '-', 63 - '_')
+ * TODO:
+ * - encoding: exclude padding characters by default,
+ * - decoding: calculate a number of missing padding characters
+ * based on a number of base64url encoded octets
+ *
+ * - once the above two points are addressed, consider extracting
+ * most of Base64Utility into Base64EncoderDecoder and extending it
+ * with Base64UrlEncoderDecoder to minimize the duplication
+ *
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.logging.Logger;
+
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.Base64Exception;
+
+
+public final class Base64UrlUtility {
+
+ private static final Logger LOG = LogUtils.getL7dLogger(Base64UrlUtility.class);
+
+ private static final String ENCODED_PAD = "%3D";
+
+ // Base 64 URL character set
+ //
+ private static final char[] BCS = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+ 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
+ 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
+ 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', '-', '_'
+ };
+
+ // base 64 wadding
+ private static final char PAD = '=';
+
+ // size of base 64 decode table
+ private static final int BDTSIZE = 128;
+
+ // base 64 decode table
+ private static final byte[] BDT = new byte[128];
+
+
+ private static final int PAD_SIZE0 = 1;
+ private static final int PAD_SIZE4 = 2;
+ private static final int PAD_SIZE8 = 3;
+
+ // class static intializer for building decode table
+ static {
+ for (int i = 0; i < BDTSIZE; i++) {
+ BDT[i] = Byte.MAX_VALUE;
+ }
+
+ for (int i = 0; i < BCS.length; i++) {
+ BDT[BCS[i]] = (byte)i;
+ }
+ }
+
+
+ private Base64UrlUtility() {
+ //utility class, never constructed
+ }
+
+ /**
+ * The <code>decode_chunk</code> routine decodes a chunk of data
+ * into its native encoding.
+ *
+ * base64 encodes each 3 octets of data into 4 characters from a
+ * limited 64 character set. The 3 octets are joined to form
+ * 24 bits which are then split into 4 x 6bit values. Each 6 bit
+ * value is then used as an index into the 64 character table of
+ * base64 chars. If the total data length is not a 3 octet multiple
+ * the '=' char is used as padding for the final 4 char group,
+ * either 1 octet + '==' or 2 octets + '='.
+ *
+ * @param id The input data to be processed
+ * @param o The offset from which to begin processing
+ * @param l The length (bound) at which processing is to end
+ * @return The decoded data
+ * @exception Base64Exception Thrown is processing fails due to
+ * formatting exceptions in the encoded data
+ */
+ public static byte[] decodeChunk(char[] id,
+ int o,
+ int l)
+ throws Base64Exception {
+
+ // Keep it simple - must be >= 4. Unpadded
+ // base64 data contain < 3 octets is invalid.
+ //
+ if ((l - o) < 4) {
+ return null;
+ }
+
+ char[] ib = new char[4];
+ int ibcount = 0;
+
+ // cryan. Calc the num of octets. Each 4 chars of base64 chars
+ // (representing 24 bits) encodes 3 octets.
+ //
+ int octetCount = 3 * (l / 4);
+
+ // Final 4 chars may contain 3 octets or padded to contain
+ // 1 or 2 octets.
+ //
+ if (id[l - 1] == PAD) {
+ // TT== means last 4 chars encode 8 bits (ie subtract 2)
+ // TTT= means last 4 chars encode 16 bits (ie subtract 1)
+ octetCount -= (id[l - 2] == PAD) ? 2 : 1;
+ }
+
+ byte[] ob = new byte[octetCount];
+ int obcount = 0;
+
+ for (int i = o; i < o + l && i < id.length; i++) {
+ if (id[i] == PAD
+ || id[i] < BDT.length
+ && BDT[id[i]] != Byte.MAX_VALUE) {
+
+ ib[ibcount++] = id[i];
+
+ // Decode each 4 char sequence.
+ //
+ if (ibcount == ib.length) {
+ ibcount = 0;
+ obcount += processEncodeme(ib, ob, obcount);
+ }
+ }
+ }
+
+ if (obcount != ob.length) {
+ byte []tmp = new byte[obcount];
+ System.arraycopy(ob, 0, tmp, 0, obcount);
+ ob = tmp;
+ }
+
+ return ob;
+ }
+
+ public static byte[] decode(String id) throws Base64Exception {
+ int count = 0;
+ while (id.endsWith(ENCODED_PAD)) {
+ id = id.substring(0, id.length() - ENCODED_PAD.length());
+ count++;
+ }
+ for (int i = 0; i < count; i++) {
+ id += PAD;
+ }
+
+ try {
+ char[] cd = id.toCharArray();
+ return decodeChunk(cd, 0, cd.length);
+ } catch (Exception e) {
+ LOG.warning("Invalid base64 encoded string : " + id);
+ throw new Base64Exception(new Message("BASE64_RUNTIME_EXCEPTION", LOG), e);
+ }
+ }
+
+ public static void decode(char[] id,
+ int o,
+ int l,
+ OutputStream ostream)
+ throws Base64Exception {
+
+ try {
+ ostream.write(decodeChunk(id, o, l));
+ } catch (Exception e) {
+ LOG.warning("Invalid base64 encoded string : " + new String(id));
+ throw new Base64Exception(new Message("BASE64_RUNTIME_EXCEPTION", LOG), e);
+ }
+ }
+
+ public static void decode(String id,
+ OutputStream ostream)
+ throws Base64Exception {
+
+ try {
+ char[] cd = id.toCharArray();
+ ostream.write(decodeChunk(cd, 0, cd.length));
+ } catch (IOException ioe) {
+ throw new Base64Exception(new Message("BASE64_DECODE_IOEXCEPTION", LOG), ioe);
+ } catch (Exception e) {
+ LOG.warning("Invalid base64 encoded string : " + id);
+ throw new Base64Exception(new Message("BASE64_RUNTIME_EXCEPTION", LOG), e);
+ }
+ }
+
+ // Returns base64 representation of specified byte array.
+ //
+ public static String encode(byte[] id) {
+ char[] cd = encodeChunk(id, 0, id.length);
+ return new String(cd, 0, cd.length);
+ }
+
+ // Returns base64 representation of specified byte array.
+ //
+ public static char[] encodeChunk(byte[] id,
+ int o,
+ int l) {
+ if (l <= 0) {
+ return null;
+ }
+
+ char[] out;
+
+ // If not a multiple of 3 octets then a final padded 4 char
+ // slot is needed.
+ //
+ if ((l - o) % 3 == 0) {
+ out = new char[l / 3 * 4];
+ } else {
+ out = new char[l / 3 * 4 + 4];
+ }
+
+ int rindex = o;
+ int windex = 0;
+ int rest = l - o;
+
+ while (rest >= 3) {
+ int i = ((id[rindex] & 0xff) << 16)
+ + ((id[rindex + 1] & 0xff) << 8)
+ + (id[rindex + 2] & 0xff);
+
+ out[windex++] = BCS[i >> 18];
+ out[windex++] = BCS[(i >> 12) & 0x3f];
+ out[windex++] = BCS[(i >> 6) & 0x3f];
+ out[windex++] = BCS[i & 0x3f];
+ rindex += 3;
+ rest -= 3;
+ }
+
+ if (rest == 1) {
+ int i = id[rindex] & 0xff;
+ out[windex++] = BCS[i >> 2];
+ out[windex++] = BCS[(i << 4) & 0x3f];
+ out[windex++] = PAD;
+ out[windex++] = PAD;
+ } else if (rest == 2) {
+ int i = ((id[rindex] & 0xff) << 8) + (id[rindex + 1] & 0xff);
+ out[windex++] = BCS[i >> 10];
+ out[windex++] = BCS[(i >> 4) & 0x3f];
+ out[windex++] = BCS[(i << 2) & 0x3f];
+ out[windex++] = PAD;
+ }
+ return out;
+ }
+
+ //
+ // Outputs base64 representation of the specified byte array
+ // to a byte stream.
+ //
+ public static void encodeChunk(byte[] id,
+ int o,
+ int l,
+ OutputStream ostream) throws Base64Exception {
+ try {
+ ostream.write(new String(encodeChunk(id, o, l)).getBytes());
+ } catch (IOException e) {
+ throw new Base64Exception(new Message("BASE64_ENCODE_IOEXCEPTION", LOG), e);
+ }
+ }
+
+ public static String encode(String value) throws Base64Exception {
+ StringWriter writer = new StringWriter();
+ Base64UrlUtility.encode(value, writer);
+ return writer.toString();
+ }
+
+ public static void encode(String value, Writer writer) throws Base64Exception {
+ byte[] chunk = null;
+ try {
+ chunk = value.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException ex) {
+ // won't happen
+ }
+ Base64UrlUtility.encode(chunk, 0, chunk.length, writer);
+
+ }
+
+
+ // Outputs base64 representation of the specified byte
+ // array to a character stream.
+ //
+ public static void encode(byte[] id,
+ int o,
+ int l,
+ Writer writer) throws Base64Exception {
+ try {
+ writer.write(encodeChunk(id, o, l));
+ } catch (IOException e) {
+ throw new Base64Exception(new Message("BASE64_ENCODE_WRITER_IOEXCEPTION", LOG), e);
+ }
+ }
+
+
+ //---- Private static methods --------------------------------------
+
+ /**
+ * The <code>process</code> routine processes an atomic base64
+ * unit of encoding (encodeme) into its native encoding. This class is
+ * used by decode routines to do the grunt work of decoding
+ * base64 encoded information
+ *
+ * @param ib Input character buffer of encoded bytes
+ * @param ob Output byte buffer of decoded bytes
+ * @param p Pointer to the encodeme of interest
+ * @return The decoded encodeme
+ * @exception Base64Exception Thrown is processing fails due to
+ * formatting exceptions in the encoded data
+ */
+ private static int processEncodeme(char[] ib,
+ byte[] ob,
+ int p)
+ throws Base64Exception {
+
+
+ int spad = PAD_SIZE8;
+ if (ib[3] == PAD) {
+ spad = PAD_SIZE4;
+ }
+ if (ib[2] == PAD) {
+ spad = PAD_SIZE0;
+ }
+
+ int b0 = BDT[ib[0]];
+ int b1 = BDT[ib[1]];
+ int b2 = BDT[ib[2]];
+ int b3 = BDT[ib[3]];
+
+ switch (spad) {
+ case PAD_SIZE0:
+ ob[p] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
+ return PAD_SIZE0;
+ case PAD_SIZE4:
+ ob[p++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
+ ob[p] = (byte)(b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
+ return PAD_SIZE4;
+ case PAD_SIZE8:
+ ob[p++] = (byte)(b0 << 2 & 0xfc | b1 >> 4 & 0x3);
+ ob[p++] = (byte)(b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
+ ob[p] = (byte)(b2 << 6 & 0xc0 | b3 & 0x3f);
+ return PAD_SIZE8;
+ default:
+ // We should never get here
+ throw new IllegalStateException();
+ }
+ }
+
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Base64UrlUtility.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Base64UrlUtility.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Constants.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Constants.java?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Constants.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Constants.java Thu Feb 21 15:57:24 2013
@@ -0,0 +1,35 @@
+/**
+ * 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.saml;
+
+public final class Constants {
+ public static final String SAML2_BEARER_GRANT =
+ "urn:ietf:params:oauth:grant-type:saml2-bearer";
+ public static final String CLIENT_GRANT_ASSERTION_PARAM = "assertion";
+
+ public static final String CLIENT_AUTH_ASSERTION_PARAM = "client_assertion";
+ public static final String CLIENT_AUTH_ASSERTION_TYPE = "client_assertion_type";
+ public static final String CLIENT_AUTH_SAML2_BEARER =
+ "urn:ietf:params:oauth:client-assertion-type:saml2-bearer";
+
+
+ private Constants() {
+
+ }
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Constants.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/Constants.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Added: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/SamlOAuthValidator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/SamlOAuthValidator.java?rev=1448696&view=auto
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/SamlOAuthValidator.java (added)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/SamlOAuthValidator.java Thu Feb 21 15:57:24 2013
@@ -0,0 +1,174 @@
+/**
+ * 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.saml;
+
+import java.util.List;
+
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+
+import org.apache.cxf.jaxrs.impl.UriInfoImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants;
+import org.apache.ws.security.saml.ext.AssertionWrapper;
+import org.apache.ws.security.saml.ext.builder.SAML2Constants;
+import org.opensaml.saml2.core.Audience;
+import org.opensaml.saml2.core.AudienceRestriction;
+import org.opensaml.saml2.core.Conditions;
+import org.opensaml.saml2.core.Issuer;
+import org.opensaml.saml2.core.SubjectConfirmation;
+import org.opensaml.saml2.core.SubjectConfirmationData;
+
+public class SamlOAuthValidator {
+ private String accessTokenServiceAddress;
+ private String issuer;
+ private String clientAddress;
+ private boolean subjectConfirmationDataRequired;
+ public SamlOAuthValidator() {
+ }
+
+
+ public void setSubjectConfirmationDataRequired(boolean required) {
+ subjectConfirmationDataRequired = required;
+ }
+
+ public void setAccessTokenServiceAddress(String address) {
+ accessTokenServiceAddress = address;
+ }
+
+ public void setIssuer(String value) {
+ issuer = value;
+ }
+
+ public void setClientAddress(String value) {
+ issuer = value;
+ }
+
+ public void validate(Message message, AssertionWrapper wrapper) {
+
+ Conditions cs = wrapper.getSaml2().getConditions();
+ validateAudience(message, cs);
+
+ if (issuer != null) {
+ String actualIssuer = getIssuer(wrapper);
+ String expectedIssuer = OAuthConstants.CLIENT_ID.equals(issuer)
+ ? wrapper.getSaml2().getSubject().getNameID().getValue() : issuer;
+ if (actualIssuer == null || !actualIssuer.equals(expectedIssuer)) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+ }
+ if (!validateAuthenticationSubject(message, cs, wrapper.getSaml2().getSubject())) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+ }
+
+ private String getIssuer(AssertionWrapper assertionW) {
+ Issuer samlIssuer = assertionW.getSaml2().getIssuer();
+ return samlIssuer == null ? null : samlIssuer.getValue();
+ }
+
+ private void validateAudience(Message message, Conditions cs) {
+ String absoluteAddress = getAbsoluteTargetAddress(message);
+
+ List<AudienceRestriction> restrictions = cs.getAudienceRestrictions();
+ for (AudienceRestriction ar : restrictions) {
+ List<Audience> audiences = ar.getAudiences();
+ for (Audience a : audiences) {
+ if (absoluteAddress.equals(a.getAudienceURI())) {
+ return;
+ }
+ }
+ }
+ throw new NotAuthorizedException(errorResponse());
+ }
+
+ private String getAbsoluteTargetAddress(Message m) {
+ if (accessTokenServiceAddress == null) {
+ return new UriInfoImpl(m).getAbsolutePath().toString();
+ }
+ if (!accessTokenServiceAddress.startsWith("http")) {
+ String httpBasePath = (String)m.get("http.base.path");
+ return UriBuilder.fromUri(httpBasePath)
+ .path(accessTokenServiceAddress)
+ .build()
+ .toString();
+ } else {
+ return accessTokenServiceAddress;
+ }
+ }
+
+ private boolean validateAuthenticationSubject(Message m,
+ Conditions cs,
+ org.opensaml.saml2.core.Subject subject) {
+ if (subject.getSubjectConfirmations() == null) {
+ return false;
+ }
+ // We need to find a Bearer Subject Confirmation method
+ for (SubjectConfirmation subjectConf : subject.getSubjectConfirmations()) {
+ if (SAML2Constants.CONF_BEARER.equals(subjectConf.getMethod())) {
+ validateSubjectConfirmation(m, cs, subjectConf.getSubjectConfirmationData());
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Validate a (Bearer) Subject Confirmation
+ */
+ private void validateSubjectConfirmation(Message m,
+ Conditions cs,
+ SubjectConfirmationData subjectConfData) {
+ if (subjectConfData == null) {
+ if (!subjectConfirmationDataRequired
+ && cs.getNotOnOrAfter() != null && !cs.getNotOnOrAfter().isBeforeNow()) {
+ return;
+ }
+ throw new NotAuthorizedException(errorResponse());
+ }
+
+ // Recipient must match assertion consumer URL
+ String recipient = subjectConfData.getRecipient();
+ if (recipient == null || !recipient.equals(getAbsoluteTargetAddress(m))) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+
+ // We must have a NotOnOrAfter timestamp
+ if (subjectConfData.getNotOnOrAfter() == null
+ || subjectConfData.getNotOnOrAfter().isBeforeNow()) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+
+ //TODO: replay cache, same as with SAML SSO case
+
+ // Check address
+ if (subjectConfData.getAddress() != null
+ && (clientAddress == null || !subjectConfData.getAddress().equals(clientAddress))) {
+ throw new NotAuthorizedException(errorResponse());
+ }
+
+
+ }
+
+ private static Response errorResponse() {
+ return Response.status(401).build();
+ }
+}
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/SamlOAuthValidator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/rs/security/oauth-parent/oauth2-saml/src/main/java/org/apache/cxf/rs/security/oauth2/saml/SamlOAuthValidator.java
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/OAuthClientUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/OAuthClientUtils.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/OAuthClientUtils.java (original)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/OAuthClientUtils.java Thu Feb 21 15:57:24 2013
@@ -152,11 +152,67 @@ public final class OAuthClientUtils {
public static ClientAccessToken getAccessToken(WebClient accessTokenService,
Consumer consumer,
AccessTokenGrant grant,
+ boolean setAuthorizationHeader) {
+ return getAccessToken(accessTokenService, consumer, grant, null, setAuthorizationHeader);
+ }
+
+ /**
+ * Obtains the access token from OAuth AccessToken Service
+ * using the initialized web client
+ * @param accessTokenService the AccessToken client
+ * @param grant {@link AccessTokenGrant} grant
+ * @param extraParams extra parameters
+ * @return {@link ClientAccessToken} access token
+ * @throws OAuthServiceException
+ */
+ public static ClientAccessToken getAccessToken(WebClient accessTokenService,
+ AccessTokenGrant grant)
+ throws OAuthServiceException {
+ return getAccessToken(accessTokenService, null, grant, null, false);
+ }
+
+ /**
+ * Obtains the access token from OAuth AccessToken Service
+ * using the initialized web client
+ * @param accessTokenService the AccessToken client
+ * @param grant {@link AccessTokenGrant} grant
+ * @param extraParams extra parameters
+ * @return {@link ClientAccessToken} access token
+ * @throws OAuthServiceException
+ */
+ public static ClientAccessToken getAccessToken(WebClient accessTokenService,
+ AccessTokenGrant grant,
+ Map<String, String> extraParams)
+ throws OAuthServiceException {
+ return getAccessToken(accessTokenService, null, grant, extraParams, false);
+ }
+
+ /**
+ * Obtains the access token from OAuth AccessToken Service
+ * using the initialized web client
+ * @param accessTokenService the AccessToken client
+ * @param consumer {@link Consumer} representing the registered client.
+ * @param grant {@link AccessTokenGrant} grant
+ * @param extraParams extra parameters
+ * @param setAuthorizationHeader if set to true then HTTP Basic scheme
+ * will be used to pass client id and secret, otherwise they will
+ * be passed in the form payload
+ * @return {@link ClientAccessToken} access token
+ * @throws OAuthServiceException
+ */
+ public static ClientAccessToken getAccessToken(WebClient accessTokenService,
+ Consumer consumer,
+ AccessTokenGrant grant,
+ Map<String, String> extraParams,
boolean setAuthorizationHeader)
throws OAuthServiceException {
Form form = new Form(grant.toMap());
-
+ if (extraParams != null) {
+ for (Map.Entry<String, String> entry : extraParams.entrySet()) {
+ form.getData().add(entry.getKey(), entry.getValue());
+ }
+ }
if (consumer != null) {
if (setAuthorizationHeader) {
StringBuilder sb = new StringBuilder();
@@ -229,18 +285,6 @@ public final class OAuthClientUtils {
}
}
- /**
- * Creates OAuth Authorization header with Bearer scheme
- * @param consumer represents the registered client
- * @param accessToken the access token
- * @return the header value
- */
- @Deprecated
- public static String createAuthorizationHeader(Consumer consumer,
- ClientAccessToken accessToken)
- throws OAuthServiceException {
- return createAuthorizationHeader(accessToken);
- }
/**
* Creates OAuth Authorization header with Bearer scheme
Modified: cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/owner/ResourceOwnerGrant.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/owner/ResourceOwnerGrant.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/owner/ResourceOwnerGrant.java (original)
+++ cxf/trunk/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/grants/owner/ResourceOwnerGrant.java Thu Feb 21 15:57:24 2013
@@ -27,10 +27,16 @@ import org.apache.cxf.rs.security.oauth2
public class ResourceOwnerGrant implements AccessTokenGrant {
private String ownerName;
private String ownerPassword;
+ private String scope;
public ResourceOwnerGrant(String name, String password) {
+ this(name, password, null);
+ }
+
+ public ResourceOwnerGrant(String name, String password, String scope) {
this.ownerName = name;
this.ownerPassword = password;
+ this.scope = scope;
}
public String getType() {
@@ -42,6 +48,9 @@ public class ResourceOwnerGrant implemen
map.putSingle(OAuthConstants.GRANT_TYPE, OAuthConstants.RESOURCE_OWNER_GRANT);
map.putSingle(OAuthConstants.RESOURCE_OWNER_NAME, ownerName);
map.putSingle(OAuthConstants.RESOURCE_OWNER_PASSWORD, ownerPassword);
+ if (scope != null) {
+ map.putSingle(OAuthConstants.SCOPE, scope);
+ }
return map;
}
Modified: cxf/trunk/rt/rs/security/oauth-parent/pom.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/oauth-parent/pom.xml?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/oauth-parent/pom.xml (original)
+++ cxf/trunk/rt/rs/security/oauth-parent/pom.xml Thu Feb 21 15:57:24 2013
@@ -44,6 +44,7 @@
<modules>
<module>oauth</module>
<module>oauth2</module>
+ <module>oauth2-saml</module>
</modules>
</project>
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/CryptoLoader.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/CryptoLoader.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/CryptoLoader.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/common/CryptoLoader.java Thu Feb 21 15:57:24 2013
@@ -41,6 +41,15 @@ public class CryptoLoader {
private static final String CRYPTO_CACHE = "rs-security-xml-crypto.cache";
+ public Crypto loadCrypto(String cryptoResource) throws IOException, WSSecurityException {
+ URL url = ClassLoaderUtils.getResource(cryptoResource, this.getClass());
+ if (url != null) {
+ return loadCryptoFromURL(url);
+ } else {
+ return null;
+ }
+ }
+
public Crypto getCrypto(Message message,
String cryptoKey,
String propKey)
@@ -54,8 +63,8 @@ public class CryptoLoader {
if (o == null) {
return null;
}
-
- crypto = getCryptoCache(message).get(o);
+ Map<Object, Crypto> cryptoCache = getCryptoCache(message);
+ crypto = cryptoCache != null ? cryptoCache.get(o) : null;
if (crypto != null) {
return crypto;
}
@@ -73,15 +82,13 @@ public class CryptoLoader {
url = manager.resolveResource((String)o, URL.class);
}
if (url != null) {
- Properties props = new Properties();
- InputStream in = url.openStream();
- props.load(in);
- in.close();
- crypto = CryptoFactory.getInstance(props);
+ crypto = loadCryptoFromURL(url);
} else {
crypto = CryptoFactory.getInstance((String)o);
}
- getCryptoCache(message).put(o, crypto);
+ if (cryptoCache != null) {
+ cryptoCache.put(o, crypto);
+ }
return crypto;
} finally {
if (orig != null) {
@@ -90,16 +97,29 @@ public class CryptoLoader {
}
}
+ public static Crypto loadCryptoFromURL(URL url) throws IOException, WSSecurityException {
+ Properties props = new Properties();
+ InputStream in = url.openStream();
+ props.load(in);
+ in.close();
+ return CryptoFactory.getInstance(props);
+ }
+
public final Map<Object, Crypto> getCryptoCache(Message message) {
- EndpointInfo info = message.getExchange().get(Endpoint.class).getEndpointInfo();
- synchronized (info) {
- Map<Object, Crypto> o =
- CastUtils.cast((Map<?, ?>)info.getProperty(CRYPTO_CACHE));
- if (o == null) {
- o = new ConcurrentHashMap<Object, Crypto>();
- info.setProperty(CRYPTO_CACHE, o);
+ Endpoint endpoint = message.getExchange().get(Endpoint.class);
+ if (endpoint != null) {
+ EndpointInfo info = endpoint.getEndpointInfo();
+ synchronized (info) {
+ Map<Object, Crypto> o =
+ CastUtils.cast((Map<?, ?>)info.getProperty(CRYPTO_CACHE));
+ if (o == null) {
+ o = new ConcurrentHashMap<Object, Crypto>();
+ info.setProperty(CRYPTO_CACHE, o);
+ }
+ return o;
}
- return o;
+ } else {
+ return null;
}
}
}
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/AbstractSamlInHandler.java Thu Feb 21 15:57:24 2013
@@ -82,20 +82,38 @@ public abstract class AbstractSamlInHand
protected void validateToken(Message message, InputStream tokenStream) {
- Document doc = null;
+ Element token = readToken(message, tokenStream);
+ validateToken(message, token);
+
+ }
+
+ protected Element readToken(Message message, InputStream tokenStream) {
+
try {
- doc = DOMUtils.readXml(new InputStreamReader(tokenStream, "UTF-8"));
+ Document doc = DOMUtils.readXml(new InputStreamReader(tokenStream, "UTF-8"));
+ return doc.getDocumentElement();
} catch (Exception ex) {
throwFault("Assertion can not be read as XML document", ex);
}
- validateToken(message, doc.getDocumentElement());
+ return null;
}
protected void validateToken(Message message, Element tokenElement) {
+ validateToken(message, toWrapper(tokenElement));
+ }
+
+ protected AssertionWrapper toWrapper(Element tokenElement) {
+ try {
+ return new AssertionWrapper(tokenElement);
+ } catch (Exception ex) {
+ throwFault("Assertion can not be validated", ex);
+ }
+ return null;
+ }
+
+ protected void validateToken(Message message, AssertionWrapper assertion) {
try {
- AssertionWrapper assertion = new AssertionWrapper(tokenElement);
-
RequestData data = new RequestData();
if (assertion.isSigned()) {
WSSConfig cfg = WSSConfig.getNewInstance();
@@ -112,6 +130,8 @@ public abstract class AbstractSamlInHand
message.getContextualProperty(WSHandlerConstants.ENABLE_REVOCATION)));
assertion.verifySignature(data, null);
assertion.parseHOKSubject(data, null);
+ } else if (getTLSCertificates(message) == null) {
+ throwFault("Assertion must be signed", null);
}
if (samlValidator != null) {
Credential credential = new Credential();
@@ -158,7 +178,7 @@ public abstract class AbstractSamlInHand
// to rt/rs/security
LOG.warning(error);
Response response = Response.status(401).entity(error).build();
- throw ex != null ? new NotAuthorizedException(ex, response) : new NotAuthorizedException(response);
+ throw ex != null ? new NotAuthorizedException(response, ex) : new NotAuthorizedException(response);
}
/**
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SAMLUtils.java Thu Feb 21 15:57:24 2013
@@ -93,15 +93,27 @@ public final class SAMLUtils {
public static AssertionWrapper createAssertion(Message message) throws Fault {
CallbackHandler handler = SecurityUtils.getCallbackHandler(
- message, SAMLUtils.class, SecurityConstants.SAML_CALLBACK_HANDLER);
+ message, SAMLUtils.class, SecurityConstants.SAML_CALLBACK_HANDLER);
+ boolean selfSignAssertion =
+ MessageUtils.getContextualBoolean(
+ message, SecurityConstants.SELF_SIGN_SAML_ASSERTION, false
+ );
+ return createAssertion(message, handler, selfSignAssertion);
+ }
+
+ public static AssertionWrapper createAssertion(Message message,
+ CallbackHandler handler) {
+ return createAssertion(message, handler, true);
+ }
+
+ public static AssertionWrapper createAssertion(Message message,
+ CallbackHandler handler,
+ boolean selfSignAssertion) throws Fault {
+
SAMLParms samlParms = new SAMLParms();
samlParms.setCallbackHandler(handler);
try {
AssertionWrapper assertion = new AssertionWrapper(samlParms);
- boolean selfSignAssertion =
- MessageUtils.getContextualBoolean(
- message, SecurityConstants.SELF_SIGN_SAML_ASSERTION, false
- );
if (selfSignAssertion) {
//--- This code will be moved to a common utility class
Crypto crypto = new CryptoLoader().getCrypto(message,
@@ -129,4 +141,50 @@ public final class SAMLUtils {
}
}
+
+ public static AssertionWrapper createAssertion(CallbackHandler handler,
+ SelfSignInfo info) throws Fault {
+
+ SAMLParms samlParms = new SAMLParms();
+ samlParms.setCallbackHandler(handler);
+ try {
+ AssertionWrapper assertion = new AssertionWrapper(samlParms);
+ assertion.signAssertion(info.getUser(),
+ info.getPassword(),
+ info.getCrypto(),
+ false);
+ return assertion;
+ } catch (Exception ex) {
+ StringWriter sw = new StringWriter();
+ ex.printStackTrace(new PrintWriter(sw));
+ LOG.warning(sw.toString());
+ throw new Fault(new RuntimeException(ex.getMessage() + ", stacktrace: " + sw.toString()));
+ }
+
+ }
+
+ public static class SelfSignInfo {
+ private Crypto crypto;
+ private String user;
+ private String password;
+
+ public SelfSignInfo(Crypto crypto, String user, String password) {
+ this.crypto = crypto;
+ this.user = user;
+ this.password = password;
+ }
+
+ public Crypto getCrypto() {
+ return crypto;
+ }
+ public String getUser() {
+ return user;
+ }
+ public String getPassword() {
+ return password;
+ }
+ public void setPassword(String password) {
+ this.password = password;
+ }
+ }
}
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormInHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormInHandler.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormInHandler.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormInHandler.java Thu Feb 21 15:57:24 2013
@@ -19,19 +19,15 @@
package org.apache.cxf.rs.security.saml;
-import java.io.InputStream;
-import java.lang.annotation.Annotation;
import java.net.URI;
-import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
-import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.jaxrs.ext.form.Form;
-import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.jaxrs.impl.UriInfoImpl;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.provider.FormEncodingProvider;
+import org.apache.cxf.jaxrs.utils.FormUtils;
import org.apache.cxf.message.Message;
public class SamlFormInHandler extends AbstractSamlBase64InHandler {
@@ -39,10 +35,9 @@ public class SamlFormInHandler extends A
private static final String SAML_ELEMENT = "SAMLToken";
private static final String SAML_RELAY_STATE = "RelayState";
- private FormEncodingProvider<Form> provider = new FormEncodingProvider<Form>();
+ private FormEncodingProvider<Form> provider = new FormEncodingProvider<Form>(true);
public SamlFormInHandler() {
- provider.setExpectedEncoded(true);
}
public Response handleRequest(Message message, ClassResourceInfo resourceClass) {
@@ -63,14 +58,12 @@ public class SamlFormInHandler extends A
return Response.status(302).location(URI.create(samlRequestURI)).build();
}
}
- // restore input stream
- CachedOutputStream os = new CachedOutputStream();
form.getData().remove(SAML_ELEMENT);
form.getData().remove(SAML_RELAY_STATE);
+
+ // restore input stream
try {
- provider.writeTo(form, Form.class, Form.class, new Annotation[]{},
- MediaType.APPLICATION_FORM_URLENCODED_TYPE, new MetadataMap<String, Object>(), os);
- message.setContent(InputStream.class, os.getInputStream());
+ FormUtils.restoreForm(provider, form, message);
} catch (Exception ex) {
throwFault(ex.getMessage(), ex);
}
@@ -79,10 +72,7 @@ public class SamlFormInHandler extends A
private Form readFormData(Message message) {
try {
- return provider.readFrom(Form.class, Form.class,
- new Annotation[]{}, MediaType.APPLICATION_FORM_URLENCODED_TYPE,
- new MetadataMap<String, String>(),
- message.getContent(InputStream.class));
+ return FormUtils.readForm(provider, message);
} catch (Exception ex) {
throwFault("Error reading the form", ex);
}
Modified: cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormOutInterceptor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormOutInterceptor.java?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormOutInterceptor.java (original)
+++ cxf/trunk/rt/rs/security/xml/src/main/java/org/apache/cxf/rs/security/saml/SamlFormOutInterceptor.java Thu Feb 21 15:57:24 2013
@@ -57,7 +57,7 @@ public class SamlFormOutInterceptor exte
String encodedToken = encodeToken(assertionWrapper.assertionToString());
- form.set(SAML_ELEMENT, encodedToken);
+ updateForm(form, encodedToken);
} catch (Exception ex) {
StringWriter sw = new StringWriter();
ex.printStackTrace(new PrintWriter(sw));
@@ -67,8 +67,12 @@ public class SamlFormOutInterceptor exte
}
+ protected void updateForm(Form form, String encodedToken) {
+ form.set(SAML_ELEMENT, encodedToken);
+ }
+
@SuppressWarnings("unchecked")
- private Form getRequestForm(Message message) {
+ protected Form getRequestForm(Message message) {
Object ct = message.get(Message.CONTENT_TYPE);
if (ct == null || !MediaType.APPLICATION_FORM_URLENCODED.equalsIgnoreCase(ct.toString())) {
return null;
Modified: cxf/trunk/systests/rs-security/pom.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/rs-security/pom.xml?rev=1448696&r1=1448695&r2=1448696&view=diff
==============================================================================
--- cxf/trunk/systests/rs-security/pom.xml (original)
+++ cxf/trunk/systests/rs-security/pom.xml Thu Feb 21 15:57:24 2013
@@ -83,6 +83,11 @@
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
+ <artifactId>cxf-rt-rs-security-oauth2-saml</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${project.version}</version>
</dependency>