cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject [1/2] cxf git commit: Refactored STS REST implementation to be able to return different token formats
Date Fri, 12 Feb 2016 15:28:36 GMT
Repository: cxf
Updated Branches:
  refs/heads/master 97f3ac75f -> 4660cd8ca


Refactored STS REST implementation to be able to return different token formats


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/ad71b7a7
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/ad71b7a7
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/ad71b7a7

Branch: refs/heads/master
Commit: ad71b7a77803354ceff3c4bcdcc8baf8364a24cb
Parents: 97f3ac7
Author: Colm O hEigeartaigh <coheigea@apache.org>
Authored: Fri Feb 12 15:23:28 2016 +0000
Committer: Colm O hEigeartaigh <coheigea@apache.org>
Committed: Fri Feb 12 15:23:28 2016 +0000

----------------------------------------------------------------------
 .../cxf/sts/rest/RESTSecurityTokenService.java  |  21 ++-
 .../sts/rest/RESTSecurityTokenServiceImpl.java  |  93 +++++++++-
 .../cxf/systest/sts/rest/STSRESTTest.java       | 181 +++++++++++++++++--
 3 files changed, 272 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/ad71b7a7/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenService.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenService.java
b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenService.java
index 0766862..3768e16 100644
--- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenService.java
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenService.java
@@ -59,14 +59,27 @@ public interface RESTSecurityTokenService {
     
     @GET
     @Path("{tokenType}")
-    @Produces({
-        MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON
-    })
-    Response getToken(@PathParam("tokenType") String tokenType, @QueryParam("keyType") String
keyType,
+    @Produces(MediaType.APPLICATION_XML)
+    Response getXMLToken(@PathParam("tokenType") String tokenType, @QueryParam("keyType")
String keyType,
         @QueryParam("claim") List<String> requestedClaims,
         @QueryParam("appliesTo") String appliesTo,
         @QueryParam("wstrustResponse") @DefaultValue("false") boolean wstrustResponse);
     
+    @GET
+    @Path("{tokenType}")
+    @Produces("application/json;qs=0.8")
+    Response getJSONToken(@PathParam("tokenType") @DefaultValue("jwt") String tokenType,

+        @QueryParam("keyType") String keyType,
+        @QueryParam("claim") List<String> requestedClaims,
+        @QueryParam("appliesTo") String appliesTo);
+    
+    @GET
+    @Path("{tokenType}")
+    @Produces("text/plain;qs=0.9")
+    Response getPlainToken(@PathParam("tokenType") String tokenType, @QueryParam("keyType")
String keyType,
+        @QueryParam("claim") List<String> requestedClaims,
+        @QueryParam("appliesTo") String appliesTo);
+    
     @POST
     @Produces({
         MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON

http://git-wip-us.apache.org/repos/asf/cxf/blob/ad71b7a7/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenServiceImpl.java
----------------------------------------------------------------------
diff --git a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenServiceImpl.java
b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenServiceImpl.java
index dd01d0a..b13f54a 100644
--- a/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenServiceImpl.java
+++ b/services/sts/sts-core/src/main/java/org/apache/cxf/sts/rest/RESTSecurityTokenServiceImpl.java
@@ -19,11 +19,15 @@
 
 package org.apache.cxf.sts.rest;
 
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
 import java.security.Principal;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.logging.Logger;
+import java.util.zip.Deflater;
 
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
@@ -31,9 +35,14 @@ import javax.xml.bind.JAXBElement;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.Base64Exception;
+import org.apache.cxf.common.util.Base64Utility;
+import org.apache.cxf.common.util.CompressionUtils;
+import org.apache.cxf.common.util.PropertyUtils;
 import org.apache.cxf.helpers.DOMUtils;
 import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.message.Message;
 import org.apache.cxf.phase.PhaseInterceptorChain;
 import org.apache.cxf.security.SecurityContext;
 import org.apache.cxf.security.transport.TLSSessionInfo;
@@ -48,6 +57,7 @@ import org.apache.cxf.ws.security.sts.provider.model.RequestSecurityTokenType;
 import org.apache.cxf.ws.security.sts.provider.model.RequestedSecurityTokenType;
 import org.apache.cxf.ws.security.sts.provider.model.UseKeyType;
 import org.apache.cxf.ws.security.trust.STSUtils;
+import org.apache.wss4j.common.util.DOM2Writer;
 import org.apache.wss4j.dom.WSConstants;
 import org.apache.xml.security.exceptions.XMLSecurityException;
 import org.apache.xml.security.keys.content.X509Data;
@@ -60,6 +70,7 @@ public class RESTSecurityTokenServiceImpl extends SecurityTokenServiceImpl
imple
 
     private static final String CLAIM_TYPE = "ClaimType";
     private static final String CLAIM_TYPE_NS = "http://schemas.xmlsoap.org/ws/2005/05/identity";
+    private static final Logger LOG = LogUtils.getL7dLogger(RESTSecurityTokenServiceImpl.class);
 
     static {
         DEFAULT_CLAIM_TYPE_MAP = new HashMap<String, String>();
@@ -94,9 +105,10 @@ public class RESTSecurityTokenServiceImpl extends SecurityTokenServiceImpl
imple
     private List<String> defaultClaims;
 
     private boolean requestClaimsOptional = true;
+    private boolean useDeflateEncoding = true;
 
     @Override
-    public Response getToken(String tokenType, String keyType, 
+    public Response getXMLToken(String tokenType, String keyType, 
                              List<String> requestedClaims, String appliesTo,
                              boolean wstrustResponse) {
         RequestSecurityTokenResponseType response = 
@@ -110,12 +122,46 @@ public class RESTSecurityTokenServiceImpl extends SecurityTokenServiceImpl
imple
         }
         
         RequestedSecurityTokenType requestedToken = getRequestedSecurityToken(response);
+        return Response.ok(requestedToken.getAny()).build();
+    }
+    
+    @Override
+    public Response getJSONToken(String tokenType, String keyType, 
+                             List<String> requestedClaims, String appliesTo) {
+        if (!"jwt".equals(tokenType)) {
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        }
+        RequestSecurityTokenResponseType response = 
+            issueToken(tokenType, keyType, requestedClaims, appliesTo);
+        
+        RequestedSecurityTokenType requestedToken = getRequestedSecurityToken(response);
+        
+        // Discard the XML Wrapper + create a new JSON Wrapper
+        String token = ((Element)requestedToken.getAny()).getTextContent();
+        return Response.ok(new JSONWrapper(token)).build();
+    }
+    
+    @Override
+    public Response getPlainToken(String tokenType, String keyType, 
+                             List<String> requestedClaims, String appliesTo) {
+        RequestSecurityTokenResponseType response = 
+            issueToken(tokenType, keyType, requestedClaims, appliesTo);
+        
+        RequestedSecurityTokenType requestedToken = getRequestedSecurityToken(response);
         
         if ("jwt".equals(tokenType)) {
             // Discard the wrapper here
             return Response.ok(((Element)requestedToken.getAny()).getTextContent()).build();
         } else {
-            return Response.ok(requestedToken.getAny()).build();
+            // Base-64 encode the token + return it
+            try {
+                String encodedToken = 
+                    encodeToken(DOM2Writer.nodeToString((Element)requestedToken.getAny()));
+                return Response.ok(encodedToken).build();
+            } catch (Exception ex) {
+                LOG.warning(ex.getMessage());
+                return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+            }
         }
     }
     
@@ -168,7 +214,7 @@ public class RESTSecurityTokenServiceImpl extends SecurityTokenServiceImpl
imple
                     JAXBElement<UseKeyType> useKey = of.createUseKey(useKeyType);
                     request.getAny().add(useKey);
                 } catch (XMLSecurityException ex) {
-                    // TODO
+                    LOG.warning(ex.getMessage());
                 }
             }
         }
@@ -337,4 +383,43 @@ public class RESTSecurityTokenServiceImpl extends SecurityTokenServiceImpl
imple
         return PhaseInterceptorChain.getCurrentMessage();
     }
 
+    public void setUseDeflateEncoding(boolean deflate) {
+        useDeflateEncoding = deflate;
+    }
+    
+    protected String encodeToken(String assertion) throws Base64Exception {
+        byte[] tokenBytes = assertion.getBytes(StandardCharsets.UTF_8);
+
+        if (useDeflateEncoding) {
+            tokenBytes = CompressionUtils.deflate(tokenBytes, getDeflateLevel(), true);
+        }
+        StringWriter writer = new StringWriter();
+        Base64Utility.encode(tokenBytes, 0, tokenBytes.length, writer);
+        return writer.toString();
+    }
+    
+    private static int getDeflateLevel() {
+        Integer level = null;
+        
+        Message m = PhaseInterceptorChain.getCurrentMessage();
+        if (m != null) {
+            level = PropertyUtils.getInteger(m, "deflate.level");
+        }
+        if (level == null) {
+            level = Deflater.DEFLATED;
+        }
+        return level;
+    }
+    
+    private static class JSONWrapper {
+        private String token;
+        
+        public JSONWrapper(String token) {
+            this.token = token;
+        }
+        
+        public String getToken() {
+            return token;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/ad71b7a7/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/rest/STSRESTTest.java
----------------------------------------------------------------------
diff --git a/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/rest/STSRESTTest.java
b/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/rest/STSRESTTest.java
index b25a204..cae4f0c 100644
--- a/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/rest/STSRESTTest.java
+++ b/services/sts/systests/basic/src/test/java/org/apache/cxf/systest/sts/rest/STSRESTTest.java
@@ -19,7 +19,10 @@
 package org.apache.cxf.systest.sts.rest;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
@@ -38,6 +41,8 @@ import org.w3c.dom.Element;
 
 import org.apache.cxf.Bus;
 import org.apache.cxf.bus.spring.SpringBusFactory;
+import org.apache.cxf.common.util.Base64Utility;
+import org.apache.cxf.common.util.CompressionUtils;
 import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.cxf.rs.security.jose.jwa.SignatureAlgorithm;
 import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactConsumer;
@@ -117,7 +122,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml2.0");
         
         Response response = client.get();
@@ -149,7 +154,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml1.1");
         
         Response response = client.get();
@@ -181,7 +186,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml1.1");
         client.query("keyType", SYMMETRIC_KEY_KEYTYPE);
         
@@ -223,7 +228,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml2.0");
         client.query("keyType", PUBLIC_KEY_KEYTYPE);
         
@@ -265,7 +270,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml1.1");
         client.query("keyType", BEARER_KEYTYPE);
         
@@ -305,7 +310,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml2.0");
         client.query("appliesTo", DEFAULT_ADDRESS);
         
@@ -338,7 +343,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml2.0");
         client.query("appliesTo", "https://localhost:8081/tripleit/");
         
@@ -365,7 +370,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml2.0");
         
         // First check that the role isn't usually in the generated token
@@ -427,7 +432,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml2.0");
         client.query("wstrustResponse", "true");
         
@@ -703,7 +708,44 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
     }
     
     @org.junit.Test
-    public void testIssueJWTToken() throws Exception {
+    public void testIssueSAML2TokenPlain() throws Exception {
+        SpringBusFactory bf = new SpringBusFactory();
+        URL busFile = STSRESTTest.class.getResource("cxf-client.xml");
+
+        Bus bus = bf.createBus(busFile.toString());
+        SpringBusFactory.setDefaultBus(bus);
+        SpringBusFactory.setThreadDefaultBus(bus);
+        
+        String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
+        WebClient client = WebClient.create(address, busFile.toString());
+
+        client.accept("text/plain");
+        client.path("saml2.0");
+        
+        Response response = client.get();
+        String encodedAssertion = response.readEntity(String.class);
+        assertNotNull(encodedAssertion);
+        
+        byte[] deflatedToken = Base64Utility.decode(encodedAssertion);
+        InputStream inputStream = CompressionUtils.inflate(deflatedToken);
+        Document doc = 
+            StaxUtils.read(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+        
+        // Process the token
+        List<WSSecurityEngineResult> results = processToken(doc.getDocumentElement());
+
+        assertTrue(results != null && results.size() == 1);
+        SamlAssertionWrapper assertion = 
+            (SamlAssertionWrapper)results.get(0).get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(assertion != null);
+        assertTrue(assertion.getSaml2() != null && assertion.getSaml1() == null);
+        assertTrue(assertion.isSigned());
+
+        bus.shutdown(true);
+    }
+    
+    @org.junit.Test
+    public void testIssueJWTTokenPlain() throws Exception {
         SpringBusFactory bf = new SpringBusFactory();
         URL busFile = STSRESTTest.class.getResource("cxf-client.xml");
 
@@ -714,7 +756,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/json").accept("application/json");
+        client.accept("text/plain");
         client.path("jwt");
         
         Response response = client.get();
@@ -736,7 +778,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/json").accept("application/json");
+        client.accept("text/plain");
         client.path("jwt");
         client.query("appliesTo", DEFAULT_ADDRESS);
         
@@ -759,7 +801,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/json").accept("application/json");
+        client.accept("text/plain");
         client.path("jwt");
         
         // First check that the role isn't usually in the generated token
@@ -849,7 +891,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("application/xml");
         client.path("saml2.0");
         
         // 1. Get a token via GET
@@ -928,7 +970,7 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
         WebClient client = WebClient.create(address, busFile.toString());
 
-        client.type("application/xml").accept("application/xml");
+        client.accept("text/plain");
         client.path("jwt");
         
         // 1. Get a token via GET
@@ -991,6 +1033,115 @@ public class STSRESTTest extends AbstractBusClientServerTestBase {
         bus.shutdown(true);
     }
     
+    @org.junit.Test
+    public void testIssueJWTTokenXMLWrapper() throws Exception {
+        SpringBusFactory bf = new SpringBusFactory();
+        URL busFile = STSRESTTest.class.getResource("cxf-client.xml");
+
+        Bus bus = bf.createBus(busFile.toString());
+        SpringBusFactory.setDefaultBus(bus);
+        SpringBusFactory.setThreadDefaultBus(bus);
+        
+        String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
+        WebClient client = WebClient.create(address, busFile.toString());
+
+        client.accept("application/xml");
+        client.path("jwt");
+        
+        Response response = client.get();
+        Document assertionDoc = response.readEntity(Document.class);
+        assertNotNull(assertionDoc);
+        
+        // Discard XML wrapper
+        validateJWTToken(assertionDoc.getDocumentElement().getFirstChild().getTextContent(),
null);
+    }
+    
+    @org.junit.Test
+    public void testIssueJWTTokenJSONWrapper() throws Exception {
+        SpringBusFactory bf = new SpringBusFactory();
+        URL busFile = STSRESTTest.class.getResource("cxf-client.xml");
+
+        Bus bus = bf.createBus(busFile.toString());
+        SpringBusFactory.setDefaultBus(bus);
+        SpringBusFactory.setThreadDefaultBus(bus);
+        
+        String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
+        WebClient client = WebClient.create(address, busFile.toString());
+
+        client.accept("application/json");
+        client.path("jwt");
+        
+        client.get();
+    }
+    
+    @org.junit.Test
+    public void testDefaultSAMLFormat() throws Exception {
+        SpringBusFactory bf = new SpringBusFactory();
+        URL busFile = STSRESTTest.class.getResource("cxf-client.xml");
+
+        Bus bus = bf.createBus(busFile.toString());
+        SpringBusFactory.setDefaultBus(bus);
+        SpringBusFactory.setThreadDefaultBus(bus);
+        
+        String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
+        WebClient client = WebClient.create(address, busFile.toString());
+
+        client.accept("*");
+        client.path("saml");
+        
+        Response response = client.get();
+        // It should be XML
+        Document doc = response.readEntity(Document.class);
+        assertNotNull(doc);
+    }
+    
+    @org.junit.Test
+    public void testDefaultJWTFormat() throws Exception {
+        SpringBusFactory bf = new SpringBusFactory();
+        URL busFile = STSRESTTest.class.getResource("cxf-client.xml");
+
+        Bus bus = bf.createBus(busFile.toString());
+        SpringBusFactory.setDefaultBus(bus);
+        SpringBusFactory.setThreadDefaultBus(bus);
+        
+        String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
+        WebClient client = WebClient.create(address, busFile.toString());
+
+        client.accept("*");
+        client.path("jwt");
+        
+        Response response = client.get();
+        // It should be XML
+        Document doc = response.readEntity(Document.class);
+        assertNotNull(doc);
+    }
+    
+    @org.junit.Test
+    public void testIssueSAMLTokenWithWrongAcceptType() throws Exception {
+        SpringBusFactory bf = new SpringBusFactory();
+        URL busFile = STSRESTTest.class.getResource("cxf-client.xml");
+
+        Bus bus = bf.createBus(busFile.toString());
+        SpringBusFactory.setDefaultBus(bus);
+        SpringBusFactory.setThreadDefaultBus(bus);
+        
+        String address = "https://localhost:" + STSPORT + "/SecurityTokenService/token";
+        WebClient client = WebClient.create(address, busFile.toString());
+
+        client.accept("application/json");
+        client.path("saml2.0");
+        
+        Response response = client.get();
+        try {
+            response.readEntity(Document.class);
+            fail("Failure expected on an bad accept type");
+        } catch (Exception ex) {
+            // expected
+        }
+
+        bus.shutdown(true);
+    }
+    
     private Element validateSAMLSecurityTokenResponse(
         RequestSecurityTokenResponseType securityResponse, boolean saml2
     ) throws Exception {


Mime
View raw message