java - Inject SecurityContext info and Request Body into @BeanParam -
currently i'm rendering command object in messagebodyreader
i'd able in @beanparam
:
inject field derived
securitycontext
(is there somewhere hook in conversion?).have field inject has been materialised
messagebodyreader
.
is possible ?
note: go down update. guess is possible use @beanparam
. though need inject securitycontext
bean , extract name info.
there's no way achieve corrected. could use @beanparam
messagebodyreader
way doing, imo that's more of hack anything. instead, way achieve use framework components way supposed used, involves custom parameter injection.
to achieve this, need 2 things, valuefactoryprovider
provide parameter values, , injectionresolver
own custom annotation. won't explaining example below, can find explanation in
you can run below example junit test. included 1 class. these dependencies used.
<dependency> <groupid>org.glassfish.jersey.test-framework.providers</groupid> <artifactid>jersey-test-framework-provider-grizzly2</artifactid> <version>2.19</version> <scope>test</scope> </dependency> <dependency> <groupid>org.glassfish.jersey.media</groupid> <artifactid>jersey-media-json-jackson</artifactid> <version>2.19</version> <scope>test</scope> </dependency>
and here test
import java.io.ioexception; import java.lang.annotation.elementtype; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; import java.lang.annotation.target; import java.security.principal; import javax.inject.inject; import javax.inject.singleton; import javax.ws.rs.consumes; import javax.ws.rs.post; import javax.ws.rs.path; import javax.ws.rs.produces; import javax.ws.rs.client.entity; import javax.ws.rs.container.containerrequestcontext; import javax.ws.rs.container.containerrequestfilter; import javax.ws.rs.container.prematching; import javax.ws.rs.core.mediatype; import javax.ws.rs.core.response; import javax.ws.rs.core.securitycontext; import org.glassfish.hk2.api.factory; import org.glassfish.hk2.api.injectionresolver; import org.glassfish.hk2.api.servicelocator; import org.glassfish.hk2.api.typeliteral; import org.glassfish.hk2.utilities.binding.abstractbinder; import org.glassfish.jersey.server.containerrequest; import org.glassfish.jersey.server.resourceconfig; import org.glassfish.jersey.server.internal.inject.abstractcontainerrequestvaluefactory; import org.glassfish.jersey.server.internal.inject.abstractvaluefactoryprovider; import org.glassfish.jersey.server.internal.inject.multivaluedparameterextractorprovider; import org.glassfish.jersey.server.internal.inject.paraminjectionresolver; import org.glassfish.jersey.server.model.parameter; import org.glassfish.jersey.server.spi.internal.valuefactoryprovider; import org.glassfish.jersey.test.jerseytest; import static org.junit.assert.assertequals; import org.junit.test; public class custominjectiontest extends jerseytest { @target(elementtype.parameter) @retention(retentionpolicy.runtime) public static @interface customparam { } public static class custommodel { public string name; public requestbody body; } public static class requestbody { public string message; } public static class customparamvaluefactory extends abstractcontainerrequestvaluefactory<custommodel> { @override public custommodel provide() { containerrequest request = getcontainerrequest(); string name = request.getsecuritycontext().getuserprincipal().getname(); requestbody body = request.readentity(requestbody.class); custommodel model = new custommodel(); model.body = body; model.name = name; return model; } } public static class customvaluefactoryprovider extends abstractvaluefactoryprovider { @inject public customvaluefactoryprovider(multivaluedparameterextractorprovider multiprovider, servicelocator locator) { super(multiprovider, locator, parameter.source.unknown); } @override protected factory<?> createvaluefactory(parameter parameter) { if (custommodel.class == parameter.gettype() && parameter.isannotationpresent(customparam.class)) { return new customparamvaluefactory(); } return null; } } public static class customparaminjectionresolver extends paraminjectionresolver<customparam> { public customparaminjectionresolver() { super(customvaluefactoryprovider.class); } } private static class custominjectbinder extends abstractbinder { @override protected void configure() { bind(customvaluefactoryprovider.class) .to(valuefactoryprovider.class) .in(singleton.class); bind(customparaminjectionresolver.class) .to(new typeliteral<injectionresolver<customparam>>(){}) .in(singleton.class); } } private static final string principal_name = "peeskillet"; @prematching public static class securitycontextfilter implements containerrequestfilter { @override public void filter(containerrequestcontext requestcontext) throws ioexception { requestcontext.setsecuritycontext(new securitycontext(){ public principal getuserprincipal() { return new principal() { public string getname() { return principal_name; } }; } public boolean isuserinrole(string role) { return false; } public boolean issecure() { return true;} public string getauthenticationscheme() { return null; } }); } } @path("test") public static class testresource { @post @produces(mediatype.text_plain) @consumes(mediatype.application_json) public string post(@customparam custommodel model) { return model.name + ":" + model.body.message; } } @override public resourceconfig configure() { return new resourceconfig(testresource.class) .register(securitycontextfilter.class) .register(new custominjectbinder()); } @test public void should_return_name_with_body() { requestbody body = new requestbody(); body.message = "hello world"; response response = target("test").request() .post(entity.json(body)); assertequals(200, response.getstatus()); string responsebody = response.readentity(string.class); assertequals(principal_name + ":" + body.message, responsebody); system.out.println(responsebody); } }
note read request body containerrequest
inside customparamvaluefactory
. same requestbody
sent in json request in @test
.
update
so surprise, is possible use @beanparam
. here following bean used test
public static class custommodel { @context public securitycontext securitycontext; public requestbody body; } public static class requestbody { public string message; }
the difference previous test instead of name
securitycontext.principal
, need inject entire securitycontext
. there's no way inject name principal
, manually.
the thing surprised me though, able inject requestbody
entity. didn't know possible.
here complete test
import java.io.ioexception; import java.security.principal; import javax.ws.rs.beanparam; import javax.ws.rs.consumes; import javax.ws.rs.post; import javax.ws.rs.path; import javax.ws.rs.produces; import javax.ws.rs.client.entity; import javax.ws.rs.container.containerrequestcontext; import javax.ws.rs.container.containerrequestfilter; import javax.ws.rs.container.prematching; import javax.ws.rs.core.context; import javax.ws.rs.core.mediatype; import javax.ws.rs.core.response; import javax.ws.rs.core.securitycontext; import org.glassfish.jersey.server.resourceconfig; import org.glassfish.jersey.test.jerseytest; import static org.junit.assert.assertequals; import org.junit.test; public class custominjecttesttake2 extends jerseytest { private static final string principal_name = "peeskillet"; private static final string message = "hello world"; private static final string response = principal_name + ":" + message; public static class custommodel { @context public securitycontext securitycontext; public requestbody body; } public static class requestbody { public string message; } @prematching public static class securitycontextfilter implements containerrequestfilter { @override public void filter(containerrequestcontext requestcontext) throws ioexception { requestcontext.setsecuritycontext(new securitycontext(){ public principal getuserprincipal() { return new principal() { public string getname() { return principal_name; } }; } public boolean isuserinrole(string role) { return false; } public boolean issecure() { return true;} public string getauthenticationscheme() { return null; } }); } } @path("test") public static class testresource { @post @produces(mediatype.text_plain) @consumes(mediatype.application_json) public string post(@beanparam custommodel model) { return model.securitycontext.getuserprincipal().getname() + ":" + model.body.message; } } @override public resourceconfig configure() { return new resourceconfig(testresource.class) .register(securitycontextfilter.class); } @test public void should_return_name_with_body() { requestbody body = new requestbody(); body.message = "hello world"; response response = target("test").request() .post(entity.json(body)); assertequals(200, response.getstatus()); string responsebody = response.readentity(string.class); assertequals(response, responsebody); system.out.println(responsebody); } }
see also:
Comments
Post a Comment