Trying to implement oAuth2 Authentication in Springboot Websocket(Without STOMP and SOCKETJS) in before handshake
.
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
private final Logger LOG = LoggerFactory.getLogger(getClass());
#Autowired
private NotificationService notificationService;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(notificationService, "/notification").addInterceptors(new HttpSessionHandshakeInterceptor()
{
#Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
#Nullable Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
#Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
boolean b = super.beforeHandshake(request, response,
wsHandler, attributes) &&
((PreAuthenticatedAuthenticationToken)
request.getPrincipal()).isAuthenticated();
return b;
}
}).setAllowedOrigins("*");
Above code throws null pointer exception
Related
I need to send a websocket message to the user after the handshake, without waiting the user to send something.
I tried to use afterHandshake in a HandshakeInterceptor, however possibly the user is not identified yet.
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private final ApplicationContext applicationContext;
WebSocketConfig(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/reply");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setHandshakeHandler(new UserHandshakeHandler())
.addInterceptors(new MessagesHandshakeInterceptor(applicationContext));
}
}
public record MessagesHandshakeInterceptor(
ApplicationContext applicationContext) implements HandshakeInterceptor {
#Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler handler, Map<String, Object> attributes) {
return true;
}
#Override
public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response,
WebSocketHandler handler, Exception exception) {
//send the message to the user
applicationContext.getBean(SimpMessagingTemplate.class)
.convertAndSendToUser(user, "/reply", message);
}
}
public class UserHandshakeHandler extends DefaultHandshakeHandler {
#Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler handler,
Map<String, Object> attributes) {
return () -> userId;
}
}
Im using graphql-java-kickstart/graphql-spring-boot and I'd like to create an interceptor to add an HTTP header after processing the request.
When I'm sending a graphql request to the backend the the interceptor is not triggered. But some calls trigger the interceptor. For example when I'm opening /graphiql in my browser I see that the interceptor is triggered but when I send a graphql request from graphiql client it is not. Any idea why? Anybody got experience with this?
My config looks like this:
#Configuration
public class InterceptorConfig implements WebMvcConfigurer {
#Autowired
private TestInterceptor testInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor).addPathPatterns("/**");
}
}
Also my Interceptor:
#Slf4j
#Component
public class TestInterceptor extends HandlerInterceptorAdapter {
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
// post processing
log.info("hello there");
}
}
I have following interceptor that successfully works in my project:
My WebConfig:
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestInterceptor);
}
#Autowired
private ControllerExecInterceptor requestInterceptor;
}
Where ControllerExecInterceptor defined as:
#Component
public class ControllerExecInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws AccessDeniedException, Exception {
// ...
}
#Override
public boolean postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws {
// ...
}
}
I am trying to use WebRequestInterceptor but i don't know how can i configure it in spring boot, as if I implement WebMvcConfigurer interface it requires a HandlerInterceptor object so i cannot assign my interceptor to it. Any help would be highly appreciated.
Interceptor class:
public class CustomerStateInterceptor implements WebRequestInterceptor {
#Resource(name = "customerStateRequestProcessor")
private CustomerStateRequestProcessor customerStateRequestProcessor;
#Override
public void preHandle(WebRequest webRequest) {
customerStateRequestProcessor.process(webRequest);
}
#Override
public void postHandle(WebRequest webRequest, ModelMap modelMap) {
//unimplemented
}
#Override
public void afterCompletion(WebRequest webRequest, Exception e) {
//unimplemented
}
}
and config class:
#Configuration
public class InterceptorConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CustomerStateInterceptor()); // <-- Error here.
}
}
You supposed to implement HandlerInterceptor from org.springframework.web.servlet package and not WebRequestInterceptor.
Update
You can just wrap with WebRequestHandlerInterceptorAdapter:
#Configuration
public class InterceptorConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(
new WebRequestHandlerInterceptorAdapter(
new CustomerStateInterceptor()));
}
}
Add filter class to your package and please try the code below -
public class RequestValidateFilter extends GenericFilterBean {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
try {
request = new RequestWrapper(httpServletRequest);
chain.doFilter(request, response);
} catch (Exception e) {
throw new ServletException();
}
}
}
FilterClass :
#Configuration
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.addFilterBefore(requestValidateFilter(), BasicAuthenticationFilter.class);
http.authorizeRequests().antMatchers("/projectname/**").authenticated();
http.addFilterAfter(responseValidateFilter(), BasicAuthenticationFilter.class);
}
private RequestValidateFilter requestValidateFilter() {
return new RequestValidateFilter();
}
private ReponseValidateFilter responseValidateFilter() {
return new ReponseValidateFilter();
}
}
in SpringBoot2.0.0.RELESAEversion
use WebMvcConfigurer configure MyWebMvcConfigurer
#Configuration
public class MyMvcConfig implements WebMvcConfigurer{
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TestHandlerInterceptors()).addPathPatterns("/**");
}
}
public class TestHandlerInterceptors implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
static resource cannot be loaded when preHandle method returning false
Instead of implementing WebMvcConfigurer, you can extend WebMvcConfigurerAdapter Which will give you default implementation.
For static resources, you can override as below.
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations(new String[] {"classpath:/","classpath:/public/"});
}
I want to implement my own authentication with spring. To keep things simple at first I'm going to implement the first step without any session, but an HTTP-Authorization header sent in every request.
I've read the documentation, many tutorials and of course searched on stackoverflow, but I couldn't fix it.
What I have is a filter (RequestFilter), which extracts the Authorization header and initializes the security context with an own Authentication (AuthenticationToken). Then there is an AuthenticationProvider (TokenAuthenticationProvider) supporting my AuthenticationToken. The filter is working, the authentication provider is not. None of the methods in TokenAuthenticationProvider are invoked. Can you help me, thanks :).
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private static final Logger LOGGER = Logger.getLogger(SecurityConfig.class.getName());
#Autowired
TokenAuthenticationProvider tokenAuthenticationProvider;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new RequestFilter(), BasicAuthenticationFilter.class)
.csrf().disable()
;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(tokenAuthenticationProvider)
;
}
}
#Component
public class TokenAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOGGER = Logger.getLogger(TokenAuthenticationProvider.class.getName());
#Autowired
ClientRepository clientRepository;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
final String authToken = authentication.getCredentials().toString();
LOGGER.severe("AUTH TOKEN: " + authToken);
return Optional.ofNullable(clientRepository.findByAuthToken(authToken))
.map((Client client) -> new AuthenticationToken(client.getId(), client.getAuthToken()))
.orElseThrow(() -> new AccessDeniedException(""));
}
#Override
public boolean supports(Class<?> authentication) {
LOGGER.severe(authentication.getName());
return AuthenticationToken.class.isAssignableFrom(authentication);
}
}
public class RequestFilter extends OncePerRequestFilter {
private final Logger LOGGER = Logger.getLogger(RequestFilter.class.getName());
#Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
LOGGER.severe("RequestFilter works");
Optional.ofNullable(request.getHeader("Authorization"))
.ifPresent((String token) -> SecurityContextHolder
.getContext()
.setAuthentication(new AuthenticationToken(token))
);
chain.doFilter(request, response);
}
}
public class AuthenticationToken extends AbstractAuthenticationToken {
private final String credentials;
private final Long principal;
public AuthenticationToken(String credentials) {
this(null, credentials);
setAuthenticated(false);
}
public AuthenticationToken(Long principal, String credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
setAuthenticated(true);
}
#Override
public Object getCredentials() {
return credentials;
}
#Override
public Object getPrincipal() {
return principal;
}
}
#RestController
public class HttpGateController {
private static final Logger LOGGER = Logger.getLogger(HttpGateController.class.getName());
#RequestMapping(
name="/gate",
method= RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
public String gateAction(#RequestBody String request) {
Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.map(Authentication::getCredentials)
.map(ObjectUtils::nullSafeToString)
.ifPresent(LOGGER::severe);
return request;
}
#RequestMapping("/status")
public String statusAction() {
return "It works.";
}
}