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 @beanparammessagebodyreader 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