[java-plugin-shibd-saml] branch dev/StateMgmtWIP updated: Fix a bug and add a unit test with RelayState included.

Codeberg noreply at shibboleth.net
Tue Apr 28 19:44:42 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch dev/StateMgmtWIP
in repository java-plugin-shibd-saml.

View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd-saml/commit/0411efb320f0a953c1b205202ec8599383ad4e17

The following commit(s) were added to refs/heads/dev/StateMgmtWIP by this push:
     new 0411efb  Fix a bug and add a unit test with RelayState included.
0411efb is described below

commit 0411efb320f0a953c1b205202ec8599383ad4e17
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Tue Apr 28 15:44:30 2026 -0400

    Fix a bug and add a unit test with RelayState included.
---
 .../idp/flows/sp/consumer/saml2/saml2-beans.xml    |   3 +-
 .../flows/saml2/SAML2TokenConsumerFlowTest.java    | 212 ++++++++++++++++++---
 2 files changed, 191 insertions(+), 24 deletions(-)

diff --git a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/saml2/saml2-beans.xml b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/saml2/saml2-beans.xml
index 99f3e30..21dc7df 100644
--- a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/saml2/saml2-beans.xml
+++ b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/consumer/saml2/saml2-beans.xml
@@ -15,7 +15,8 @@
     <bean id="RecoverStateData"
         class="net.shibboleth.sp.profile.impl.RecoverStateData" scope="prototype"
         p:stateTokenLookupStrategy-ref="RelayStateLookup"
-        p:stateDataClass="net.shibboleth.sp.saml.saml2.SAMLStateData" />
+        p:stateDataClass="net.shibboleth.sp.saml.saml2.SAMLStateData"
+        p:createOutputObjects="true" />
 
     <bean id="RelayStateLookup" parent="shibboleth.Functions.Compose">
         <constructor-arg name="g">
diff --git a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2TokenConsumerFlowTest.java b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2TokenConsumerFlowTest.java
index b047e9e..61aca70 100644
--- a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2TokenConsumerFlowTest.java
+++ b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/SAML2TokenConsumerFlowTest.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
@@ -56,13 +57,23 @@ import org.opensaml.xmlsec.signature.support.SignatureException;
 import org.opensaml.xmlsec.signature.support.SignatureSupport;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.web.WebAppConfiguration;
 import org.springframework.webflow.executor.FlowExecutionResult;
 import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.spring.IdPPropertiesApplicationContextInitializer;
@@ -72,17 +83,32 @@ import net.shibboleth.shared.codec.DecodingException;
 import net.shibboleth.shared.codec.EncodingException;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.net.CookieManager;
 import net.shibboleth.shared.net.URISupport;
+import net.shibboleth.shared.net.CookieManager.SameSiteValue;
+import net.shibboleth.shared.primitive.NonnullSupplier;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.ResolverException;
 import net.shibboleth.shared.security.IdentifierGenerationStrategy;
+import net.shibboleth.shared.service.ReloadableService;
+import net.shibboleth.shared.service.ServiceableComponent;
 import net.shibboleth.shared.xml.XMLParserException;
+import net.shibboleth.sp.Agent;
+import net.shibboleth.sp.AgentCriterion;
+import net.shibboleth.sp.AgentResolver;
+import net.shibboleth.sp.Application;
 import net.shibboleth.sp.context.AgentRequestContext;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.flows.AbstractSPFlowTest;
 import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
 import net.shibboleth.sp.messaging.RemotedHttpServletResponse;
 import net.shibboleth.sp.profile.ConsumerConstants;
+import net.shibboleth.sp.saml.saml2.SAMLStateData;
 import net.shibboleth.sp.saml.saml2.profile.impl.PrepareAgentResponse;
+import net.shibboleth.sp.state.StateData;
+import net.shibboleth.sp.state.impl.CookieStateManager;
 
 /**
  * Unit test for the SP session-initiator flow.
@@ -116,18 +142,84 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
     /** ACS URL. */
     @Nonnull public static final String RESOURCE_URL = "https://sp.example.org/secure";
 
+    @Autowired
+    @Qualifier("shibboleth.sp.AgentResolver")
+    protected ReloadableService<AgentResolver> agentResolver;
+    
     @Autowired
     @Qualifier("shibboleth.SessionIDGenerator")
     protected IdentifierGenerationStrategy idGenerator;
     
     /** Dummy signing key. */
-    @Autowired @Qualifier("dummy.idp.Credential") protected Credential idpCredential;
+    @Autowired
+    @Qualifier("dummy.idp.Credential")
+    protected Credential idpCredential;
 
+    // Used to create state cookies for subsequent inclusion in mock requests to flow.
+    
+    private CookieManager cookieManager;
+    private CookieStateManager stateManager;
+    private MockHttpServletRequest request2;
+    private MockHttpServletResponse response2;
+    
     /** Constructor. */
     public SAML2TokenConsumerFlowTest() {
         super(FLOW_ID);
     }
     
+    /**
+     * Set up state manager.
+     * 
+     * @throws ComponentInitializationException
+     */
+    @BeforeClass
+    public void beforeClass() throws ComponentInitializationException {
+        cookieManager = new CookieManager();
+        cookieManager.setCookiePath("/");
+        cookieManager.setSameSite(SameSiteValue.None);
+        cookieManager.setCookieLimit(10);
+        cookieManager.setHttpServletRequestSupplier(new NonnullSupplier<HttpServletRequest>() {
+            @Nonnull public HttpServletRequest get() {
+                assert request2 != null;
+                return request2;
+            }
+        });
+        cookieManager.setHttpServletResponseSupplier(new NonnullSupplier<HttpServletResponse>() {
+            @Nonnull public HttpServletResponse get() {
+                assert response2 != null;
+                return response2;
+            }
+        });
+        cookieManager.initialize();
+        
+        stateManager = new CookieStateManager();
+        stateManager.setId("test");
+        stateManager.setCookiePrefix("__Host-shibsp_state");
+
+        final ObjectMapper mapper = new ObjectMapper();
+        mapper.registerModule(new JavaTimeModule());
+        stateManager.setObjectMapper(mapper);
+        
+        stateManager.setHttpServletRequestSupplier(new NonnullSupplier<HttpServletRequest>() {
+            @Nonnull public HttpServletRequest get() {
+                assert request2 != null;
+                return request2;
+            }
+        });
+        
+        stateManager.setCookieManager(cookieManager);
+        stateManager.initialize();
+    }
+    
+    /**
+     * Tear down state manager.
+     */
+    @AfterClass
+    public void tearDown() {
+        stateManager.destroy();
+        cookieManager.destroy();
+    }
+    
     /** Pre-test work. */
     @BeforeMethod
     public void beforeMethod() {
@@ -158,7 +250,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
     public void testErrorStatus() throws IOException {
         final Response response = buildSAMLResponse(ISSUER, StatusCode.RESPONDER, null);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -174,7 +266,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
      */
     @Test
     public void testUnverified() throws IOException {
-        final DDF input = buildRemotedPOSTResponse(buildSAMLResponse(ISSUER + "/bad", StatusCode.SUCCESS, null));
+        final DDF input = buildRemotedPOSTResponse(buildSAMLResponse(ISSUER + "/bad", StatusCode.SUCCESS, null), null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -193,7 +285,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         final Response response = buildSAMLResponse(ISSUER, StatusCode.SUCCESS, null);
         response.setIssueInstant(Instant.EPOCH);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -212,7 +304,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         final Response response = buildSAMLResponse(ISSUER, StatusCode.SUCCESS, null);
         response.setDestination(RESPONSE_URL + "/bad");
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -231,7 +323,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         final Response response = buildSAMLResponse(ISSUER, StatusCode.SUCCESS, null);
         response.getAssertions().get(0).setIssueInstant(Instant.now().minusSeconds(1800));
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -253,7 +345,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assert locality != null;
         locality.setAddress("127.0.0.1");
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -278,7 +370,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assert data != null;
         data.setAddress("127.0.0.1");
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -301,7 +393,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assert subject != null;
         subject.getSubjectConfirmations().get(0).setMethod(SubjectConfirmation.METHOD_SENDER_VOUCHES);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -326,7 +418,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assert data != null;
         data.setNotOnOrAfter(null);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -351,7 +443,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assert data != null;
         data.setRecipient(null);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -376,7 +468,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assert data != null;
         data.setRecipient(RESPONSE_URL + "/bad");
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -397,7 +489,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         final Response response = buildSAMLResponse(ISSUER, StatusCode.SUCCESS, null);
         response.getAssertions().get(0).setIssuer(SAML2ActionTestingSupport.buildIssuer(ISSUER + "bad"));
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -421,7 +513,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         issuer.setFormat(NameIDType.EMAIL);
         response.getAssertions().get(0).setIssuer(issuer);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -439,7 +531,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
     @Test
     public void testUnsigned() throws IOException {
         final Response response = buildSAMLResponse(ISSUER, StatusCode.SUCCESS, null);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -459,7 +551,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         final Response response = buildSAMLResponse(ISSUER, StatusCode.SUCCESS, null);
         response.getAssertions().get(0).setConditions(null);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -481,7 +573,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assert conditions != null;
         conditions.setNotOnOrAfter(Instant.now().minusSeconds(300));
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -504,7 +596,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         assert conditions != null;
         conditions.getAudienceRestrictions().get(0).getAudiences().get(0).setURI(AUDIENCE + "/bad");
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -524,7 +616,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
     public void testSuccess() throws IOException {
         final Response response = buildSAMLResponse(ISSUER, StatusCode.SUCCESS, null);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -537,6 +629,53 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
                 RESOURCE_URL, response.getAssertions().get(0).getAuthnStatements().get(0).getSessionIndex());
     }
 
+    /**
+     * Test successful flow with InResponseTo available.
+     * 
+     * @throws IOException
+     * @throws ResolverException 
+     */
+    @Test
+    public void testSuccessWithState() throws IOException, ResolverException {
+        
+        request2 = new MockHttpServletRequest();
+        response2 = new MockHttpServletResponse();
+        final StateData state = buildStateData("foo");
+        
+        final String stateToken;
+        
+        try (final ServiceableComponent<AgentResolver> resolver = agentResolver.getServiceableComponent()) {
+            final Agent agent = resolver.getComponent().resolveSingle(
+                    new CriteriaSet(new AgentCriterion(AGENT_ID)));
+            assert agent != null;
+            final Application app = agent.getApplication(APPLICATION_ID);
+            assert app != null;
+            stateToken = stateManager.preserveToStateToken(agent, app, state);
+        }
+        
+        final Cookie cookie = response2.getCookies()[0];
+        assert cookie != null;
+        
+        final Response response = buildSAMLResponse(ISSUER, StatusCode.SUCCESS, "foo");
+        sign(response);
+        final DDF input = buildRemotedPOSTResponse(response, stateToken);        
+        input.getmember(RemotedHttpServletRequest.STRUCTURE_NAME)
+            .addmember("headers").structure()
+            .addmember("Cookie")
+            .unsafe_string(new String(cookie.getName() + '=' + cookie.getValue()).getBytes(StandardCharsets.UTF_8));
+
+        setApplicationRequest(APPLICATION_ID, input);
+        
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+        assertFlowExecutionResult(result, FLOW_ID);
+        assertFlowExecutionOutcome(result.getOutcome());
+        final DDF output = assertOutputMessageSuccess(result);
+        assert output != null;
+        System.out.println("testSuccess output: " + output.toString());
+        validateOutputMessage(result, CollectionSupport.singleton("mail"),
+                RESOURCE_URL, response.getAssertions().get(0).getAuthnStatements().get(0).getSessionIndex());
+    }
+    
     /**
      * Test successful flow with attributes.
      * 
@@ -554,7 +693,7 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
                         CollectionSupport.listOf("staff at example.org", "employee at example.org")));
         response.getAssertions().get(0).getAttributeStatements().add(statement);
         sign(response);
-        final DDF input = buildRemotedPOSTResponse(response);
+        final DDF input = buildRemotedPOSTResponse(response, null);
         setApplicationRequest(APPLICATION_ID, input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -717,12 +856,14 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
      * Encodes a SAML response into a form POST embedded in a remoted message.
      * 
      * @param response SAML response to encode
+     * @param relayState relay state if any
      * 
      * @return input object suitable for token consumer flow
      * 
      * @throws IOException on error 
      */
-    @Nonnull private DDF buildRemotedPOSTResponse(@Nonnull final Response response) throws IOException {
+    @Nonnull private DDF buildRemotedPOSTResponse(@Nonnull final Response response, @Nullable final String relayState)
+            throws IOException {
                 
         try (final ByteArrayOutputStream sink = new ByteArrayOutputStream()) {
             XMLObjectSupport.marshallToOutputStream(response, sink);
@@ -736,8 +877,16 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
             http.addmember(RemotedHttpServletRequest.CONTENT_TYPE).string("application/x-www-form-urlencoded");
             http.addmember(RemotedHttpServletRequest.REQUEST_URL).unsafe_string(RESPONSE_URL.getBytes(StandardCharsets.UTF_8));
             
-            http.addmember(RemotedHttpServletRequest.BODY).unsafe_string(Constraint.isNotNull(URISupport.buildQuery(
-                    CollectionSupport.listOf(new Pair<>("SAMLResponse", base64))), "Query string is null").getBytes(StandardCharsets.UTF_8));
+            final List<Pair<String,String>> params;
+            if (relayState != null) {
+                params = CollectionSupport.listOf(new Pair<>("SAMLResponse", base64),
+                        new Pair<>("RelayState", relayState));
+            } else {
+                params = CollectionSupport.singletonList(new Pair<>("SAMLResponse", base64));
+            }
+            
+            http.addmember(RemotedHttpServletRequest.BODY).unsafe_string(
+                    Constraint.isNotNull(URISupport.buildQuery(params), "Query string is null").getBytes(StandardCharsets.UTF_8));
             
             return obj;
         } catch (final MarshallingException | EncodingException e) {
@@ -766,4 +915,21 @@ public class SAML2TokenConsumerFlowTest extends AbstractSPFlowTest {
         }
     }
 
+    /**
+     * Create state object.
+     * 
+     * @param requestID message ID to include
+     * 
+     * @return state object
+     */
+    @Nonnull private StateData buildStateData(@Nonnull final String requestID) {
+        final SAMLStateData data = new SAMLStateData();
+        data.setRequestID(requestID);
+        data.setRequestTime(Instant.now());
+        data.setIssuer(AUDIENCE);
+        data.setAuthenticationAuthority(ISSUER);
+        data.setRawResource(RESOURCE_URL.getBytes(StandardCharsets.UTF_8));
+        return data;
+    }
+    
 }
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list