Jersey client with RxJava conflicts with resteasy - jboss

I have a web application deployed to JBOSS. It contains dependency to jersey-rx-client-rxjava package and one of the packages has transient dependency to resteasy-jaxrs.
I have the following code.
RxObservable.newClient()
.target(fullURL)
.request()
.header("Authorization", "Bearer " + config.getApiKey())
.rx()
.post(javax.ws.rs.client.Entity.entity(context, MediaType.APPLICATION_JSON_TYPE), AIResponse.class)
.map(new Func1<AIResponse, String>() {
#Override
public String call(AIResponse res) {
return res.getType();
}
})
.subscribe(new Action1<String>() {
#Override
public void call(final String type) {
Log.info(type);
}
}, new Action1<Throwable>() {
#Override
public void call(final Throwable throwable) {
//async.resume(throwable);
Log.error(throwable.getMessage(), throwable);
}
}, new Action0() {
#Override
public void call() {
//async.resume(throwable);
Log.info("Done");
}
});
At this line, the following exception is thrown.
final JerseyInvocation invocation = (JerseyInvocation) getBuilder().build(name, entity);
Why does the build method return org.jboss.resteasy.client.jaxrs.internal.ClientInvocation, instead of JerseyInvocation?
2017-03-20 12:18:43,678 ERROR [com.optawork.bot.CustomResource] (default task-2) org.jboss.resteasy.client.jaxrs.internal.ClientInvocation cannot be cast to org.glassfish.jersey.client.JerseyInvocation: java.lang.ClassCastException: org.jboss.resteasy.client.jaxrs.internal.ClientInvocation cannot be cast to org.glassfish.jersey.client.JerseyInvocation
at org.glassfish.jersey.client.rx.rxjava.JerseyRxObservableInvoker$2.call(JerseyRxObservableInvoker.java:89)
at org.glassfish.jersey.client.rx.rxjava.JerseyRxObservableInvoker$2.call(JerseyRxObservableInvoker.java:83)
at rx.Observable.unsafeSubscribe(Observable.java:10142)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:48)
at rx.internal.operators.OnSubscribeMap.call(OnSubscribeMap.java:33)
at rx.Observable.subscribe(Observable.java:10238)
at rx.Observable.subscribe(Observable.java:10205)
at rx.Observable.subscribe(Observable.java:10086)
at ai.api.AIDataService.converse(AIDataService.java:601)

Why does the build method return org.jboss.resteasy.client.jaxrs.internal.ClientInvocation, instead of JerseyInvocation
It's just how the JAX-RS Client API is designed. When we try to call ClientBuilder.newBuilder (which is done internally), the JAX-RS API does a service lookup for any implementation of the JAX-RS Client API. If there is none, it falls back to Jersey. The problem is that when the service lookup is done, RESTEasy's client is found on the classpath.
The Jersey RX API has a from(Client) method that we can user, instead of the default newClient. This will allow us to pass an explicit JerseyClient instead of using the JAX-RS API ClientBuilder.newBuilder/newClient
// actual JerseyClient which implements Client
Client client = new JerseyClientBuilder().build();
RxObservable.from(client)
JerseyClientBuilder has pretty much the same API as the JAX-RS ClientBuilder, so you can use it pretty much the same way.

Related

How to use placeholders in dynamic camel-kafka endpoint?

I am using a dynamic endpoint to send messages to Kafka.
private static final String OUTPUT_TOPIC = "OutputTopic";
...
private void setOutputTopic(Exchange exchange) {
//some other code
exchange.setProperty(OUTPUT_TOPIC,"MyKafkaTopic");
}
...
#Override
public void configure() {
from("direct:someEndpoint")
.process(this::setOutputTopic)
...
.toD("kafka:${exchangeProperty." + OUTPUT_TOPIC + "}");
}
With Camel version 3.4.x everything worked fine. After migration to Camel version 3.14.x several tests started to fail due to optimization in KafkaSendDynamicAware that creates kafka endpoint with URI that contains unresolved placeholders and Camel test facilities does not work as before:
#MockEndpointsAndSkip("kafka:MyKafkaTopic")
...
#EndpointInject("mock:kafka:MyKafkaTopic")
private MockEndpoint mockedMyKafkaTopic;
Could you suggest the proper way how to test dynamic Kafka endpoint in this case?
You should be able to use the dynamic topic name using the property placeholder syntax {{some.property}}:
#Override
public void configure() {
from("direct:someEndpoint")
.process(this::setOutputTopic)
// ...
.toD("kafka:{{" + OUTPUT_TOPIC + "}}");
}

Different AuthenticationManager per path/route in spring security in MvC

Preamble
Since there are a lot of questions on StackOverflow about this already, I first want to ensure that this is not a duplicate and differentiate.
This is about
Having 2(or more) different AuthenticationProviders in 2 different AuthenticationManagers to be used on different routes.
Using the methods in Spring Security 5.5 not 3.x
Using a non XML configuration based approach
So the question is not about:
How to include several AuthenticationProvideres in on AuthenticationManager to offer "alternative authentications" (which most questions tend to be)
Case
Assume one has 2 custom AuthenticationProviders: CATApiTokenProvider and DOGApiTokenProvider. It is by design that we not talk about AOuth/JWT/Basic/Form providers, since they offer shortcuts.
Now we have 2 REST API endpoints /dog/endpoint and /cat/endpoint.
Question
How would one properly implement this today, with Spring Security 5.5:
We want the authentication provider CATApiTokenProvider to only be able to authenticate requests on /cat/endpoint
We want the authentication provider DOGApiTokenProvider to only be able to authenticate requests on /dog/endpoint
So one cannot authenticate with a cat token on /dog/endpoint and neither with a dog token on /cat/endpoint.
My Ideas/Approaches
a) I understand that since I have custom Cat/Dog filters, one can use the AuthenticationManagerResolver and pass one instance into the filter when creating the bean. This resolver might look like
public AuthenticationManagerResolver<HttpServletRequest> resolver()
{
return request -> {
if (request.getPathInfo().startsWith("/dog/")) {
try {
return ???;
} catch (Exception exception) {
log.error(exception);
}
}
if (request.getPathInfo().startsWith("/cat/")) {
try {
return ???;
} catch (Exception exception) {
log.error(exception);
}
}
};
}
Two questions with that would be:
how to return different authentication managers here? How to instantiate 2 different AM with each one CatAP and DogAP? Currently I use public void configure(AuthenticationManagerBuilder auth) but as far as I understand, I would only configure 'the one' AuthenticationManager and I could add DogAP and CatAP there, but this would let as having 1 AM with 2 APs, so when using this AM i could auth with the dog token on the cat endpoint
is this really the right way to implement this? I would have expected to be able to provide the AM on the SecurityConfiguration level
b) Somehow instantiate 2 different AuthenticationManagers and then use the SecurityConfiguration to assign them to different matchers.
Two questions:
what is the right way to spawn 2 different AMs with different providers?
I cannot understand how I would add an AM for a spec
http.authorizeRequests()
.antMatchers("/dog/**")
.?
You can either publish multiple filter chains or wire your own AuthenticationFilter with an AuthenticationManagerResolver
You may use AuthenticationManagerResolver to return different AuthenticationManagers. Since Spring Security 5.4.0, we don't need to extend the WebSecurityConfigurerAdapter to configure our SecurityFilterChain anymore, you can instead define a bean of SecurityFilterChain type.
I'll go into detail on wiring your own AuthenticationFilter.
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Bean
public SecurityFilterChain apiSecurity(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated());
http.addFilterBefore(apiAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
private AuthenticationFilter apiAuthenticationFilter() {
AuthenticationFilter authenticationFilter = new AuthenticationFilter(new ApiAuthenticationManagerResolver(), new BasicAuthenticationConverter());
authenticationFilter.setSuccessHandler((request, response, authentication) -> {});
return authenticationFilter;
}
public static class ApiAuthenticationManagerResolver implements AuthenticationManagerResolver<HttpServletRequest> {
private final Map<RequestMatcher, AuthenticationManager> managers = Map.of(
new AntPathRequestMatcher("/dog/**"), new DogAuthenticationProvider()::authenticate,
new AntPathRequestMatcher("/cat/**"), new CatAuthenticationProvider()::authenticate
);
#Override
public AuthenticationManager resolve(HttpServletRequest request) {
for (Map.Entry<RequestMatcher, AuthenticationManager> entry : managers.entrySet()) {
if (entry.getKey().matches(request)) {
return entry.getValue();
}
}
throw new IllegalArgumentException("Unable to resolve AuthenticationManager");
}
}
public static class DogAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication.getName().endsWith("_dog")) {
return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(),
AuthorityUtils.createAuthorityList("ROLE_DOG"));
}
throw new BadCredentialsException("Username should end with _dog");
}
#Override
public boolean supports(Class<?> authentication) {
return true;
}
}
public static class CatAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication.getName().endsWith("_cat")) {
return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(),
AuthorityUtils.createAuthorityList("ROLE_CAT"));
}
throw new BadCredentialsException("Username should end with _cat");
}
#Override
public boolean supports(Class<?> authentication) {
return true;
}
}
}
In the example above, we have two AuthenticationProviders, one for cat and other for dog. They are resolved upon an AntPathRequestMatcher matching for both /dog/** and /cat/** endpoints, inside the ApiAuthenticationManagerResolver. There is no need to defined an AuthenticationManager for each dog and cat, since AuthenticationProvider/Manager have the same interface.
The ApiAuthenticationManagerResolver is then wired inside an AuthenticationFilter in your filter chain.
You can also define two different filter chains for each endpoint, like so:
#Bean
public SecurityFilterChain dogApiSecurity(HttpSecurity http) throws Exception {
http.requestMatchers((matchers) -> matchers
.antMatchers("/dog/**"));
http.authorizeRequests((authz) -> authz
.anyRequest().authenticated());
http.httpBasic();
http.authenticationProvider(new DogAuthenticationProvider());
return http.build();
}
#Bean
public SecurityFilterChain catApiSecurity(HttpSecurity http) throws Exception {
http.requestMatchers((matchers) -> matchers
.antMatchers("/cat/**"));
http.authorizeRequests((authz) -> authz
.anyRequest().authenticated());
http.httpBasic();
http.authenticationProvider(new CatAuthenticationProvider());
return http.build();
}
Please, when defining multiple filter chains, the ordering is important, make use of the #Order annotation in those scenarios.
When you do http.requestMatcher(new AntPathRequestMatcher("/endpoint/**")); you are telling Spring Security to only call the filter chain when the request matches that path.
There is also a ticket within Spring Security's repository to provide a AuthenticationManagerResolver implementation which accepts Map<RequestMatcher, AuthenticationManager>, it would be nice if you think it makes sense, give a thumbs up there.

FrontController with RequestFactory in GWT

I am using RequestFactory with GWT. It all working fine. I have a RequestContext interface that point to my DAO methodes.
Now I want to implement some kind of security check before calling the DAO. The first thing that comes to my mind is to use a FrontController and centralize the security in it, but I don't know to implement it with the RequestFactory. Any thought ?
If you want to test whether the user is authenticated, you can use a servlet filter on the server-side and a custom RequestTransport on the client-side. See the guice-rf-activity archetype at https://github.com/tbroyer/gwt-maven-archetypes for an example.
You can also check on the method-level by using a custom ServiceLayerDecorator and implementing the invoke method, calling report() when the user isn't authorized/authenticated (and handling the onFailure on the client-side). I implemented such a thing, that authorized the user based on #RolesAllowed annotations on the service method or class: https://gist.github.com/tbroyer/6091533
Here's how I implemented the security checking:
On the server side I check to see that every RequestFactory request is associated with a user who has previously logged in. To do this, the web.xml file (in the war/WEB-INF directory) must have a mapping for the servlet class. Here's the entry from the web.xml file:
<servlet>
<servlet-name>requestFactoryServlet</servlet-name>
<servlet-class>org.greatlogic.rfexample2.server.RFERequestFactoryServlet</servlet-class>
<init-param>
<param-name>symbolMapsDirectory</param-name>
<param-value>WEB-INF/classes/symbolMaps/</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>requestFactoryServlet</servlet-name>
<url-pattern>/gwtRequest</url-pattern>
</servlet-mapping>
The RFERequestFactoryServlet class contains the following code:
public class RFERequestFactoryServlet extends RequestFactoryServlet {
#Override
protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
throws IOException, ServletException {
if (!userIsLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
else {
super.doPost(request, response);
}
}
private boolean userIsLoggedIn(final HttpServletRequest request) {
boolean result = false;
HttpSession session = request.getSession();
if (session != null) {
User user = (User)session.getAttribute("User");
result = user != null;
}
return result;
}
}
On the client side I needed to intercept every RequestFactory response to check for the SC_UNAUTHORIZED error. You have to tell the RequestFactory object to use a specific RequestTransport in the RequestFactory#initialize invocation, like this:
MyRequestFactory requestFactory = GWT.create(MyRequestFactory.class);
requestFactory.initialize(eventBus, new RFERequestTransport());
My RFERequestTransport class extends the DefaultRequestTransport class:
public class RFERequestTransport extends DefaultRequestTransport {
private final class RFERequestCallback implements RequestCallback {
private RequestCallback _requestCallback;
private RFERequestCallback(final RequestCallback requestCallback) {
_requestCallback = requestCallback;
}
#Override
public void onError(final Request request, final Throwable exception) {
_requestCallback.onError(request, exception);
}
#Override
public void onResponseReceived(final Request request, final Response response) {
if (response.getStatusCode() == Response.SC_UNAUTHORIZED) {
// the login processing goes here
}
else {
_requestCallback.onResponseReceived(request, response);
}
}
} // end of the RFERequestCallback class
#Override
protected RequestCallback createRequestCallback(final TransportReceiver receiver) {
return new RFERequestCallback(super.createRequestCallback(receiver));
}
}
When RequestFactory creates a request callback it calls my method, which creates my own version of a RequestCallback. If the user is logged in (as determined by the servlet) then it just performs the normal RequestFactory processing; otherwise, I go through the login process with the user. Part of the login process involves communication with the server to verify the login ... if the login is successful then I create an object on the server and store a reference to it in the "User" attribute - this is then checked in the userIsLoggedIn method in the servlet class.
Setup a filter in your web.xml so as every RF request is filtered to validate the session.
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>my.namespace.AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/gwtRequest</url-pattern>
</filter-mapping>
Here you have an example class, checking if a certain parameter is in session which could be set in the login process to your app, this is just an example, you could use your own mechanism.
public class AuthFilter implements Filter {
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
if (req.getSession().getAttribute("VALID_SESSION") == null) {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
if (null != filterChain) {
filterChain.doFilter(req, resp);
}
}
}

gwt - servlet path + url

I need to read data from an xml file that is under the WAR directory.
I'm using RequestBuilder for creating the GET request.
It looks like this:
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET,"customerRecord.xml");
try {
requestBuilder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
requestFailed(exception);
}
public void onResponseReceived(Request request,Response response) {
renderXML(response.getText());
}
});
} catch (RequestException ex) {
requestFailed(ex);
}
Now, the thing is that I don't want to load all of the data. I want to send a parameter that tells the server which part to bring, (let's say - how many lines of data) and then override the doGet method of the servlet and deal with the parameter.
I have 2 questions:
1) how do I declare the path of the servlet? where is the connection between the servlet and the request??
2) What do I write in the url of the RequestBuilder (instead of "customerRecord.xml")? do I need to refer to the servlet there or I can keep it like
May be You mean GWT Service?
You need to create 2 interfaces - Service and ServiceAsync and implementation of Service in server package (on same level as client package). Then You define implementation as servlet (in my JBoss 7.1 it just annotation. in older version servlet mapping):
#WebServlet(name="YourService", urlPatterns={"/%module%/YourService"})
public class YourServiceImpl extends RemoteServiceServlet implements YourService
in Your modeule.xml write:
<servlet path="/YourService" class="org.name.YourServiceImpl"/>
and in the end You can call this service from Your code
YourService.App.getInstance().getSomething(new AsyncCallback<Collection<Something>>() {
#Override
public void onFailure(Throwable caught) {
new MessagePopup("Error: " + caught.getMessage()).center();
}
#Override
public void onSuccess(Collection<Something> result) {
}
});
Interfaces You can create from Your beloved IDE. It's much simpler)
One think which still bothering me - I cannot specify path for servlet in another module.

GWT servlet filter ,How to identify special service request?

I created a app with GWT+requestfacotry(MVP)+GAE. There are some service or method exposed to GWT client ,such as
1.create
2.remove
3.query
I want to add authorization function to "create" and "remove" ,but not to "query".
I did it with servlet filter :
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
UserService userService = UserServiceFactory.getUserService();
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (!userService.isUserLoggedIn()) {
response.setHeader("login", userService.createLoginURL(request.getHeader("pageurl")));
// response.setHeader("login", userService.createLoginURL(request.getRequestURI()));
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
filterChain.doFilter(request, response);
}
My question is how to identify what request (I mean the request will route to which class and service )coming in ? There are some head fields contain the module name ,but I don't it is the security way to do.
Is it possible to get RequestFacotry relevant class from http request ?
Thanks
It's hard to do this within the servlet-filter. Instead you can provide a custom decorator within the RF ServiceLayerDecorator chain. Implementation can looks like this:
import com.google.web.bindery.requestfactory.server.ServiceLayerDecorator;
public class SecurityDecorator extends ServiceLayerDecorator {
#Override
public Object invoke( Method domainMethod, Object... args ) {
if ( !isAllowed( domainMethod) ) {
handleSecurityViolation();
}
return super.invoke( domainMethod, args );
}
}
To register the additional decorator, provide a custom RF servlet:
import com.google.web.bindery.requestfactory.server.RequestFactoryServlet;
public class SecurityAwareRequestFactoryServlet extends RequestFactoryServlet {
public SecurityAwareRequestFactoryServlet() {
super( new DefaultExceptionHandler(), new SecurityDecorator() );
}
}
and register it in your web.xml:
<servlet>
<servlet-name>gwtRequest</servlet-name>
<servlet-class>com.company.SecurityAwareRequestFactoryServlet</servlet-class>
</servlet>