JAX-RS Apache Oltu server request with JSON body - jax-rs

I am trying to implement OAuth2 in my JAX-RS application, using Apache Oltu. I have found this:
https://github.com/apache/oltu/tree/trunk/oauth-2.0/integration-tests/src/test/java/org/apache/oltu/oauth2/integration/endpoints
#POST
#Consumes("application/x-www-form-urlencoded")
#Produces("application/json")
public Response authorize(#Context HttpServletRequest request) throws OAuthSystemException
{
OAuthTokenRequest oauthRequest = null;
OAuthIssuer oauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());
try {
oauthRequest = new OAuthTokenRequest(request);
} catch (OAuthProblemException e) {
OAuthResponse res = OAuthASResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST).error(e)
.buildJSONMessage();
return Response.status(res.getResponseStatus()).entity(res.getBody()).build();
}
This works fine with application/x-www-form-urlencoded. However I want to have support for application/json too. I can't find any documentation how I extend or implement this. Is anyone familiar with this problem?
Preferably I want to reuse OAuthTokenRequest

The #Consumes and #Produces annotations from the JAX-RS api have support for an Array of Strings by default. You can declare your REST endpoint like this to support multiple formats: #Consumes({"application/x-www-form-urlencoded", "application/json"})

Related

How to trigger Quarkus OIDC-Client trigger on Header Authorization: Basic

I'm working to convert a Spring application to Quarkus. I want both Bearer and Basic Authentication to work. This will also use Keycloak Authorization Service (main reason I'm moving to Quarkus).
The quarkus.oidc configuration works great and I have no problem with the Bearer Token Authorization.
The quarkus.oidc-client configuration does contain grant-type password option that I assume I could use to convert a Authorization: Basic Header to username/password and generate a Bearer Token. This is the spot I think I'm stuck.
Do I need to extend HttpAuthenticationMechanism? The extended class would invoke the oidc-client with the client credentials, grant-type=password and username/password from the Authorization: Basic header?
application.properties
quarkus.http.auth
quarkus.http.auth.basic=true
quarkus.http.auth.permission.basic-bearer.paths=/api/config/*
quarkus.http.auth.permission.basic-bearer.policy=authenticated
#end quarkus.http.auth
#quarkus.oidc
quarkus.oidc.enabled=true
quarkus.oidc.auth-server-url=${keycloakAuthServerUrl}/realms/${keycloakRealm}
quarkus.oidc.discovery-enabled=true
quarkus.oidc.client-id=${keycloakResource}
quarkus.oidc.credentials.secret=${keycloakCredentialsSecret}
#end quarkus.oidc
#quarkus.oidc-client
quarkus.oidc-client.enabled=true
quarkus.oidc-client.auth-server-url=${keycloakAuthServerUrl}/realms/${keycloakRealm}
quarkus.oidc-client.discovery-enabled=true
quarkus.oidc-client.client-id=${keycloakResource}
quarkus.oidc-client.credentials.secret=${keycloakCredentialsSecret}
quarkus.oidc-client.grant.type=password
Do I need to add SecurityIdentity below?
#Path("/api/config")
public class ConfigController {
#Inject
Tokens tokens;
String success;
public String getSuccess() {
return success;
}
#GET
#Path("")
#Produces(MediaType.APPLICATION_JSON)
public Response sendOk() throws JsonProcessingException {
success = tokens.getAccessToken();
ObjectMapper objectMapper = new ObjectMapper();
return Response.ok(objectMapper.writeValueAsString(this)).build();
}
#GET
#Path("/owners")
#Produces(MediaType.APPLICATION_JSON)
public Response sendOwners() throws JsonProcessingException {
success = tokens.getAccessToken();
ObjectMapper objectMapper = new ObjectMapper();
return Response.ok(objectMapper.writeValueAsString(this)).build();
}
}
I was trying to get the quarkus.oidc-client to manage Basic Authorization header without need to add my own HttpAuthenticationMechanism

Block server-to-server or Postman calls to ASP.NET Core 3.1 API

I have a ASP.NET Core 3.1 API where I have not used CORS. As I understand, CORS is a browser thing. And as my ajax calls from another site on another origin is blocked to the API endpoints (which is great), I can still reach the same endpoints by using Postman or a HttpClient and GetAsync() calls.
My question is of it's possible to also block server-to-server calls (or Postman calls) to my API? Or like CORS, only allow certain origins?
Most of my endpoints are protected by a bearer JWT token, but I have an anonymous endpoint that I would like to let only origins I control (or can configure) to have access to that anonymous API.
I solved it after i bumped in to this post on stackoverflow:
How do you create a custom AuthorizeAttribute in ASP.NET Core?
I simply made a custom Authorize attribute [ApiAuthorize()], that I call this way:
[ApiController]
[ApiAuthorize(new string[] { "https://localhost:44351", "https://mysite.onthe.net" })]
public class MyInternalApiController : ControllerBase
{
...
}
It may also be implemented on the Action instead of the Controller. The implementation was done like this:
public class ApiAuthorizeAttribute : TypeFilterAttribute
{
public ApiAuthorizeAttribute(string[] origins) : base(typeof(ApiAuthorizeFilter))
{
Arguments = new object[] { origins };
}
}
public class ApiAuthorizeFilter : IAuthorizationFilter
{
readonly string[] _origins;
public ApiAuthorizeFilter(string[] origins)
{
_origins = origins;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
if (_origins == null)
return;
string referer = context.HttpContext.Request.Headers["Referer"].ToString();
if (string.IsNullOrWhiteSpace(referer) || !_origins.Any(origin => referer.StartsWith(origin, StringComparison.OrdinalIgnoreCase)))
context.Result = new ForbidResult();
}
}
Things to consider:
The implementation and check of the referer could be exact match instead of StartsWith
The handling could use RegEx or any good alternative to handle subdomains, wildcards etc
The referer could be translated to a Uri objects to get better results and variations
A jQuery ajax call gets a "403 - Forbidden" as expected, but Postman gets a "404 - Not Found". To me that does not matter, but that's something to look into if it matters.
But it covers what I need, so I'm happy with this.

Different JSON (de)serialization configs on different endpoints using Spring WebFlux

My micro service needs to communicate with 2 different services over HTTP. 1 has an API contract with snake_case JSON, while the other uses camelCase. How can I configure WebFlux to deserialize and serialize JSON with a certain Jackson ObjectMapper on a set of functional endpoints, while use another one on different endpoints?
The WebFlux documentation shows how to wire in another ObjectMapper, but this applies to all the endpoints of my API. So right now either all my JSON in snake_case or in camelCase. Cant find any resource to solve this issue, but it must be doable right?
Update: to make it clear I want to configure the web server which receives the requests from other services, not the webclient for sending http requests myself. I know how to do the latter.
you can use the #JsonNaming annotation on the classes you want to serialize/deserialize and specify what type of naming strategy you want.
jackson-advanced-annotations
Okay, so this is not the cleaned up solution, I will use this solution from our library, but the basic gist of my work around looks like this:
#Controller
public class Handler {
private ObjectMapper mapper;
public Handler(#Qualifier("snakeCaseWrapper") ObjectMapper mapper) {
this.mapper = mapper;
}
Mono<ServerResponse> returnUser(final ServerRequest request) {
//REQUEST DESERIALIZATION
var messageReader = new DecoderHttpMessageReader<>(new Jackson2JsonDecoder(mapper));
var configuredRequest = ServerRequest.create(request.exchange(), List.of(messageReader));
//RESPONSE SERIALIZATION
return configuredRequest.bodyToMono(UserDto.class)
.map(userDto -> {
try {
return mapper.writeValueAsString(userDto);
} catch (JsonProcessingException e) {
e.printStackTrace();
//properly handle the error here
return "";
}
})
.flatMap(json -> ServerResponse.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(json))
);
}
}
This is the only way I could find to programatically choose which kind of ObjectMapper I want to use for a specific endpoint/handler method for request deserialization. For response serialization, the trick was to first use the ObjectMapper to serialize the response body to a String, and put that String into the response with BodyInserters.fromObject(json) .
It works, so I'm happy with it.

How to remove "Server" header from the restlet/jetty response?

I use Restlet integration with Jetty in my project. I would need to remove the "Server" header from the response as it discloses server information. But since I use Restlet integration with Jetty (restlet, jetty, org.restlet.ext.jetty.jar) the HttpConfiguration object is instantiated inside Restlet and not in my code. So I am not able to set "_sendServerVersion" as false and hence not able to remove the server header from the response. How to remove the server header from the response in this case ?
The best way to create a Filter and remove the header through the Filter:
public class ServerFilter extends Filter {
public ServerFilter(Context context) {
super(context);
}
#Override
protected void afterHandle(Request request, Response response) {
response.getHeaders().set("Server", null);
super.afterHandle(request, response);
}
}
Then use it like:
ServerFilter serverFilter = new ServerFilter(getContext());
serverFilter.setNext(router);
return serverFilter;
See: https://javadocs.restlet.talend.com/2.4/jee/api/index.html for documentation

Jersey Client : Using ConnectionKeepAliveStrategy

Need help in applying ConnectionKeepAliveStrategy for ApacheConnector in jersey client.
For a standalone Apache Client, we can do it this way -
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
//your strategy here..
}
};
CloseableHttpClient client = HttpClients.custom()
.setKeepAliveStrategy(myStrategy)
.build();
But I couldn't find any way to apply strategy while using Jersey Client.
Tried registering the above feature class to WebClient but that did not help.
Any leads ?
Jersey 2.29.1 added support for Apache HTTP Client ConnectionKeepAliveStrategy and ConnectionReuseStrategy. Should work like this with ApacheConnector:
clientConfig.property(ApacheClientProperties.KEEPALIVE_STRATEGY, myStrategy);