Detect protocol with finatra - https

Hello I'm faily new with Finatra and wanted to know if there is a way to validate that a request was made using the https protocol?

If you want to always use HTTPS you can disable the http server server
import com.twitter.finagle.Http
import com.twitter.finatra.http.HttpServer
import com.twitter.finatra.http.routing.HttpRouter
object ExampleHttpsServerMain extends ExampleHttpsServer
class ExampleHttpsServer
extends HttpServer
with Tls {
override val defaultHttpPort: String = "" // disable the default HTTP port
override val defaultHttpsPort: String = ":443"
override def configureHttp(router: HttpRouter): Unit = {
router
.add[ExampleController]
}
}
But if you want for some specific controller or route to check if it is https for example Login should only be used via https then you can define Filters for example:
Per Route
class ExampleController #Inject()(
exampleService: ExampleService
) extends Controller {
filter[ExampleFilter].get("/ping") { request: Request =>
"pong"
}
filter[ExampleFilter]
.filter[AnotherExampleFilter]
.get("/name") { request: Request =>
response.ok.body("Bob")
}
filter(new OtherFilter).post("/foo") { request: Request =>
exampleService.do(request)
"bar"
}
}
Per Controller
import DoEverythingModule
import ExampleController
import ExampleFilter
import com.twitter.finagle.http.Request
import com.twitter.finatra.http.filters.AccessLoggingFilter
import com.twitter.finatra.http.routing.HttpRouter
import com.twitter.finatra.http.{Controller, HttpServer}
object ExampleServerMain extends ExampleServer
class ExampleServer extends HttpServer {
override val modules = Seq(
DoEverythingModule)
override def configureHttp(router: HttpRouter) {
router
.add[ExampleFilter, ExampleController]
}
}
If you check all implementations of SimpleFilter you may find some filters that you can reuse or base your filter from.

Related

calling blocking feign client from reactive spring service

I am trying to call generated feign client from reactive spring flux like this:
.doOnNext(user1 -> {
ResponseEntity<Void> response = recorderClient.createUserProfile(new UserProfileDto().principal(user1.getLogin()));
if (!response.getStatusCode().equals(HttpStatus.OK)) {
log.error("recorder backend could not create user profile for user: {} ", user1.getLogin());
throw new RuntimeException("recorder backend could not create user profile for login name" + user1.getLogin());
}
})
Call is executed, but when I try to retrieve jwt token from reactive security context ( in a requets interceptor ) like this:
public static Mono<String> getCurrentUserJWT() {
return ReactiveSecurityContextHolder
.getContext()
.map(SecurityContext::getAuthentication)
.filter(authentication -> authentication.getCredentials() instanceof String)
.map(authentication -> (String) authentication.getCredentials());
}
....
SecurityUtils.getCurrentUserJWT().blockOptional().ifPresent(s -> template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER, s)));
context is empty. As I am pretty new to reactive spring I am surely mussing something stupid and important.
Not sure how is your interceptor configured,
but in my case, i just simply implement ReactiveHttpRequestInterceptor and override apply() function
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
import reactivefeign.client.ReactiveHttpRequest;
import reactivefeign.client.ReactiveHttpRequestInterceptor;
import reactor.core.publisher.Mono;
import java.util.Collections;
#Component
public class UserFeignClientInterceptor implements ReactiveHttpRequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER = "Bearer";
#Override
public Mono<ReactiveHttpRequest> apply(ReactiveHttpRequest reactiveHttpRequest) {
return SecurityUtils.getCurrentUserJWT()
.flatMap(s -> {
reactiveHttpRequest.headers().put(AUTHORIZATION_HEADER, Collections.singletonList(String.format("%s %s", BEARER, s)));
return Mono.just(reactiveHttpRequest);
});
}
}

Spring returns EmptyCollectionEmbeddedWrapper instead of just an empty array

(Using only #RepositoryRestResource and methods defined inside the repository)When making an http request and a repository method returns no result, is there any workaround to change the returned "content" to an empty array if it really is empty , instead of :
HttpEntityMethodProcessor - Writing [Resources { content: [org.springframework.hateoas.core.EmbeddedWrappers$EmptyCollectionEmbeddedWrapp
My repo:
#RepositoryRestResource(collectionResourceRel = "some", path = "some")
public interface SomeRepository extends PagingAndSortingRepository<SomePojo, String>
{}
false:
"content": [
{
"value": [],
"rel": null,
"collectionValue": true,
"relTargetType": "xy.cxyPojo"
}
]
}
good:
"content": []
}
Edit: found the solution, it is the following:
The best and easiest solution i found finally for this so far is the following. Implement a custom ResourceProcessor, which is automatically picked up and used by spring(because of the #Component). Override the process method and in the method return a new Resource() which is initialized with an empty list, instead of the old Resource you got as an argument, add the links and all what you want and that's it. Like this:
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.ResourceProcessor;
import org.springframework.hateoas.Resources;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
#Component
public class ResourceProcessorEmpty implements ResourceProcessor<Resources<Object>>
{
#Override
public Resources<Object> process(final Resources<Object> resourceToThrowAway)
{
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// In my case i needed the request link with parameters, and the empty content[] array
Link link = new Link(request.getRequestURL().toString() + "?" + request.getQueryString());
Resources<Object> newResource = new Resources<>(Collections.emptyList());
newResource.add(link);
return newResource;
}
}
For clarification: if you use Resources<Object>, that will handle empty collections(when that "EmptyCollectionEmbeddedWrapper" dummy object would be returned), whereas Resources<Resource<Object>> will handle non-empty collections. In this case the first needs to be used.

How to access websocket from controller or another component/services?

I have a REST API, I want to send event to the client via websocket.
How to inject websocket instance in controller or another component?
Better solution is to create global module. You can then emit events from any other module/controller. A. Afir approach will create multiple instances of Gateway if you try to use it in other modules.
Note: This is just simplest solution
Create socket.module.ts
import { Module, Global } from '#nestjs/common';
import { SocketService } from './socket.service';
#Global()
#Module({
controllers: [],
providers: [SocketService],
exports: [SocketService],
})
export class SocketModule {}
socket.service.ts
import { Injectable } from '#nestjs/common';
import { Server } from 'socket.io';
#Injectable()
export class SocketService {
public socket: Server = null;
}
app.gateway.ts see afterInit function
import { WebSocketGateway, OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect, WebSocketServer } from '#nestjs/websockets';
import { Logger } from '#nestjs/common';
import { Server, Socket } from 'socket.io';
import { SocketService } from './socket/socket.service';
#WebSocketGateway()
export class AppGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
constructor(private socketService: SocketService){
}
#WebSocketServer() public server: Server;
private logger: Logger = new Logger('AppGateway');
afterInit(server: Server) {
this.socketService.socket = server;
}
handleDisconnect(client: Socket) {
this.logger.log(`Client disconnected: ${client.id}`);
}
handleConnection(client: Socket, ...args: any[]) {
this.logger.log(`Client connected: ${client.id}`);
}
}
Then import SocketModule into AppModule and you can use Socket service everywhere.
class Gateway can be injected in another component, and use the server instance.
#Controller()
export class AppController {
constructor(
private readonly appService: AppService,
private readonly messageGateway: MessageGateway
) {}
#Get()
async getHello() {
this.messageGateway.server.emit('messages', 'Hello from REST API');
return this.appService.getHello();
}
}
I suppose that #Raold missed a fact in the documentation:
Gateways should not use request-scoped providers because they must act as singletons. Each gateway encapsulates a real socket and cannot be instantiated multiple times.
So it means that we can neither instantiate the gateway class multiple times nor do it explicitly using injection scopes features.
So creating just only one gateway for one namespaces will be right and it will produce only one instance of the websocket or socket.io server.

'object%20Object' Being Appended instead of parameters.

I am attempting to make a call to the server using promises. When trying to add my parameters, it comes out as 'object%20Object'
Here is the call
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/map';
import { User } from '../models/user';
#Injectable()
export class UserService {
private baseUserUrl = 'api/User/'
constructor(private http: Http) { }
getUsers(currentPage: number): Promise<User[]> {
return this.http.get(this.baseUserUrl + 'GetUsers?currentPage=' + currentPage)
.map(resp => resp.json() as User[])
.toPromise()
}
}
I was accidentally passing an object into the method, so I wasn't accessing the property, I was accessing the object. I fixed that and removed the object and passed a property.

Usage examples for Jetty's ProxyServlet.Transparent class

I am trying to use jetty7 to build a transparent proxy setup. Idea is to hide origin servers behind the jetty server so that the incoming request can be forwarded in a transparent manner to the origin servers.
I want to know if I can use jetty's ProxyServlet.Transparent implementation to do so. If yes, can anyone give me some examples.
This example is based on Jetty-9. If you want to implement this with Jetty 8, implement the proxyHttpURI method (See Jetty 8 javadocs.). Here is some sample code.
import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.servlets.ProxyServlet;
/**
* When a request cannot be satisfied on the local machine, it asynchronously
* proxied to the destination box. Define the rule
*/
public class ContentBasedProxyServlet extends ProxyServlet {
private int remotePort = 8080;
public void setPort(int port) {
this.remotePort = port;
}
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void service(ServletRequest request, ServletResponse response) throws IOException, ServletException {
super.service(request, response);
}
/**
* Applicable to Jetty 9+ only.
*/
#Override
protected URI rewriteURI(HttpServletRequest request) {
String proxyTo = getProxyTo(request);
if (proxyTo == null)
return null;
String path = request.getRequestURI();
String query = request.getQueryString();
if (query != null)
path += "?" + query;
return URI.create(proxyTo + "/" + path).normalize();
}
private String getProxyTo(HttpServletRequest request) {
/*
* Implement this method: All the magic happens here. Use this method to figure out your destination machine address. You can maintain
* a static list of addresses, and depending on the URI or request content you can route your request transparently.
*/
}
}
Further more, you can implement a Filter that determines whether the request needs to terminate on the local machine or on the destination machine. If the request is meant for the remote machine, forward the request to this servlet.
// Declare this method call in the filter.
request.getServletContext()
.getNamedDispatcher("ContentBasedProxyServlet")
.forward(request, response);

Resources