How do I enable URL rewriting in dropwizard? I need to rewrite all urls matching a certain pattern to /.
I'm using dropwizard 0.7.1 and I'm trying to run an Angular.js app in html5 mode in the front-end and this requires url rewriting (see https://docs.angularjs.org/guide/$location under the Server side section).
you can try with this: http://www.tuckey.org/urlrewrite/
it's very symilar to mod_rewrite.
You could add a Filter like this:
environment.getApplicationContext().addFilter(
new FilterHolder(new Filter() {
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (shouldRedirect(request.getRequestURI())) {
response.sendRedirect("/");
} else {
chain.doFilter(req, res);
}
}
#Override
public void destroy() {}
}), "/*", EnumSet.allOf(DispatcherType.class));
For simple rules it seems to me that the best option is to use the Dropwizard PathRedirect RedirectBundle.
Add dropwizard-redirect-bundle to your dependencies
Register the bundle:
#Override
public void initialize(Bootstrap<?> bootstrap) {
bootstrap.addBundle(new RedirectBundle(
new PathRedirect("/old", "/new")
));
}
It supports regular expressions as well.
Just a note that for this to work with other bundles, such as static assets and HTTPS redirect, order matters. It should be:
AssetsBundle first
HttpsRedirect second
PathRedirect last
Related
I am using Spring Security and Spring Oauth2 and JWT in my API project
The default API in order to login which Spring oauth 2 provided, is /oauth/token
This API always adds "Strict-Transport-Security: max-age=31536000 ; includeSubDomains" header to the response.
But I don't want this in my situation. And I have removed HSTS with the below source code.
#EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.headers()
.httpStrictTransportSecurity().disable();
}
}
With above code, APIs I defined is removed HSTS in header. But the default API /oauth/token still return HSTS in header.
Is there any way to do this ?
Please help.
Thanks,
Tin
I just ran into the same issue.
The best solution I found is writing a filter that prevents others from setting the HSTS header in general.
#Component
#Order(value = Ordered.HIGHEST_PRECEDENCE)
public class HstsHeaderPreventionFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) {
public void setHeader(String name, String value) {
if (!name.equalsIgnoreCase("Strict-Transport-Security")) {
super.setHeader(name, value);
}
}
});
}
#Override
public void destroy() {
}
}
I am new to spring boot. I have implemented Spring Security with oAuth2 and get acesstoken successfully from spring Security. But when I try to request with token with "Authorization" header..
config.headers["Authorization"] = 'Bearer 0d634d2b-3900-4ca4-a462-cf729e8d0c72';
and my CORS filter is as :
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
if (request.getMethod()!="OPTIONS") {
chain.doFilter(req, res);
} else {
}
}
#Override
public void destroy() {
}
}
But still it given CORS issue.
Please help me where I am wrong.
Problem solve. I have send token as wrong way
config.headers["Authorization"] = 'Bearer 0d634d2b-3900-4ca4-a462-cf729e8d0c72';
right way is:
config.headers.authorization = 'Bearer 0d634d2b-3900-4ca4-a462-cf729e8d0c72';
Try to set your Access-Control-Allow-Headers like this:
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Authorization, Content-Type");
I use Spring Session and I am having issues with session management especially dealing with session expiration.
The idea is to return a custom Http Header to the client e.g. X-Application-Session-Is-New if the session has expired.
Here is what I came up with:
public class SessionDestroyedFilter extends OncePerRequestFilter {
//TODO: not always invoked!!
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (isAjaxRequest(request) && (isRequestedSessionInvalid(request) || isSessionNew(request))) {
response.addHeader("X-Application-Session-Is-New", "true");
}
filterChain.doFilter(request, response);
}
private boolean isRequestedSessionInvalid(HttpServletRequest request) {
return !request.isRequestedSessionIdValid();
}
private boolean isSessionNew(HttpServletRequest request) {
return request.getSession(false).isNew();
}
private boolean isAjaxRequest(HttpServletRequest request) {
return "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
}
}
The issue is that my filter does not seem to be always invoked upon session expiration perhaps because the request is not an ajax request and a new session ID is immediately created after that.
Can anyone please point me to an appropriate strategy to deal with session expiration on single page apps?
EDIT Following is currently not possible (instead do decoration)
Here are some related github issues (comment on them to fix them faster)
https://github.com/spring-projects/spring-session/issues/243
https://github.com/spring-projects/spring-session/issues/112
To accomplish this you have to use your own HttpSessionStrategy.
Here is an example if you are using CookieHttpSessionStrategy (the default one)
public class CustomHttpSessionStrategy extends CookieHttpSessionStrategy {
#Override
public void onInvalidateSession(HttpServletRequest request, HttpServletResponse response) {
super.onInvalidateSession(request, response);
response.addHeader("X-Application-Session-Is-New", "true");
}
}
If you want to add your header on new sessions also consider overriding onNewSession(Session, HttpServletRequest, HttpServletResponse).
This is Wrong
Please see my other answer
You should move your logic for adding X-Application-Session-Is-New after request is processed.
Try something like
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
if (isAjaxRequest(request) && (isRequestedSessionInvalid(request) || isSessionNew(request))) {
response.addHeader("X-Application-Session-Is-New", "true");
}
}
So I have the following Authorization Server condensed from this example from Dave Syer
#SpringBootApplication
public class AuthserverApplication {
public static void main(String[] args) {
SpringApplication.run(AuthserverApplication.class, args);
}
/* added later
#Configuration
#Order(Ordered.HIGHEST_PRECEDENCE)
protected static class MyWebSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http //.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
}
}*/
#Configuration
#EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends
AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "foobar".toCharArray())
.getKeyPair("test");
converter.setKeyPair(keyPair);
return converter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")
//.secret("acmesecret")
.authorizedGrantTypes(//"authorization_code", "refresh_token",
"password").scopes("openid");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authenticationManager(authenticationManager).accessTokenConverter(
jwtAccessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(
"isAuthenticated()");
}
}
}
when I run it and test it with curl
curl acme#localhost:8110/oauth/token -d grant_type=password -d client_id=acme -d username=user -d password=password
I get a JWT as respons, but as soon as I try to access the AuthServer from my Frontend (Angular JS on a different port) I get CORS error. Not becauce of missing Headers, but because the OPTION request is rejected and is missing the credentials.
Request URL:http://localhost:8110/oauth/token
Request Method:OPTIONS
Status Code:401 Unauthorized
WWW-Authenticate:Bearer realm="oauth", error="unauthorized", error_description="Full authentication is required to access this resource"
I already knew that I have to add a CorsFilter and additionally found this post where I used the the snippet for the first Answer to let the OPTIONS request access /oauth/token without credentials:
#Order(-1)
public class MyWebSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
}
}
After that I got with curl the following error:
{"timestamp":1433370068120,"status":403,"error":"Forbidden","message":"Expected CSRF token not found. Has your session expired?","path":"/oauth/token"}
So to make it simple I just added http.csrf().disable() to the configure method of MyWebSecurity class, which solves the Problem with the OPTION request, but therefore the POST request isn't working anymore and I get There is no client authentication. Try adding an appropriate authentication filter. (also with curl).
I tried to find out if I have to somehow connect MyWebSecurity class and the AuthServer, but without any luck. The original example (link in the beginning) injects as well the authenticationManager, but this changed nothing for me.
Found the reason for my Problem!
I just needed to end the filterchain and return the result immediatly if a OPTIONS request is processed by the CorsFilter!
SimpleCorsFilter.java
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCorsFilter implements Filter {
public SimpleCorsFilter() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
After that I could ignore the OPTIONS preflight request in my AuthServer =D
So the Server works as in the snipped above and you can ignore the block comment with MyWebSecurity class in the beginning.
I found a solution using the solution for the question. But I have another way to describe the solution:
#Configuration
public class WebSecurityGlobalConfig extends WebSecurityConfigurerAdapter {
....
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS);
}
...
}
I came across similar issue using following
Backend Spring Boot 1.5.8.RELEASE
Spring OAuth2 Spring OAuth 2.2.0.RELEASE w
Vuejs app using axios ajax request library
With postman everything works! When I started making request from Vuejs app then I got the following errors
OPTIONS http://localhost:8080/springboot/oauth/token 401 ()
and
XMLHttpRequest cannot load http://localhost:8080/springboot/oauth/token. Response for preflight has invalid HTTP status code 401
After reading a bit, I found out that I can instruct my Spring OAuth to ignore the OPTIONS request by overriding configure in my WebSecurityConfigurerAdapter implementation class as follow
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS);
}
Addition of the above helped but then, I came across the CORS specific error
OPTIONS http://localhost:8080/springboot/oauth/token 403 ()
and
XMLHttpRequest cannot load http://localhost:8080/springboot/oauth/token. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 403.
And solved the above issue with the help of a CorsConfig as shown below
#Configuration
public class CorsConfig {
#Bean
public FilterRegistrationBean corsFilterRegistrationBean() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.applyPermitDefaultValues();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("*"));
config.setAllowedHeaders(Arrays.asList("*"));
config.setAllowedMethods(Arrays.asList("*"));
config.setExposedHeaders(Arrays.asList("content-length"));
config.setMaxAge(3600L);
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(0);
return bean;
}
}
After addition of the above class, it works as expected. Before I go prod I will research consequences of using
web.ignoring().antMatchers(HttpMethod.OPTIONS);
as well as best practices for above Cors configuration. For now * does the job but, definitely not secure for production.
Cyril's answer helped me partially and then I came across the CorsConfig idea in this Github issue.
well, you're right! that's a solution, and it worked also for me (I had the same issue)
But let me sussgest to use a smarter CORS Filter implementation for Java:
http://software.dzhuvinov.com/cors-filter.html
This is very complete solution for Java applications.
Actually, you can see here how your point is resolved.
Using Spring Boot 2 here.
I had to do this in my AuthorizationServerConfigurerAdapter
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
Map<String, CorsConfiguration> corsConfigMap = new HashMap<>();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
//TODO: Make configurable
config.setAllowedOrigins(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
corsConfigMap.put("/oauth/token", config);
endpoints.getFrameworkEndpointHandlerMapping()
.setCorsConfigurations(corsConfigMap);
//additional settings...
}
I tried different things to solve this issue. I would say that the below was fixed this issue on my side (Using Spring Boot 2)
1-Add the below method to the below method class that extends WebSecurityConfigurerAdapter:
// CORS settings
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS);
}
2-Add the below to my class that extends AuthorizationServerConfigurerAdapter
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// enable cors for "/oauth/token"
Map<String, CorsConfiguration> corsConfigMap = new HashMap<>();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Collections.singletonList("*"));
config.setAllowedMethods(Collections.singletonList("*"));
config.setAllowedHeaders(Collections.singletonList("*"));
corsConfigMap.put("/oauth/token", config);
endpoints.getFrameworkEndpointHandlerMapping()
.setCorsConfigurations(corsConfigMap);
// add the other configuration
}
I would like to write a filter for a Facebook login, without to use the Facebook plugin. For Facebook authentification, I'll use Spring Social Facebook with annoation configuration.
The problem is who to write a filter.
I tried :
class FacebookAuthFilter extends AbstractAuthenticationProcessingFilter {
public FacebookAuthFilter() {
super("/j_facebook_security_check")
println "constructor"
}
#Override
public Authentication attemptAuthentication(HttpServletRequest arg0,
HttpServletResponse arg1) throws AuthenticationException,
IOException, ServletException {
println "attemptAuthentication"
return null;
}
}
In Bootstrap.goovy
SpringSecurityUtils.registerFilter ('facebookAuthFilter', SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order + 10)
In resources.groovy
facebookAuthFilter(FacebookAuthFilter) {
authenticationManager = ref('authenticationManager')
rememberMeServices = ref('rememberMeServices')
}
At server start, I can see "constructor" in console. But not"attemptAuthentication".
How to enter in attemptAuthentication() ? I would like the map "/auth/facebook" to attemptAuthentication() method.
Thanks
EDIT :
Hi Igor, unfortunately, it's not work.
public FacebookAuthFilter() {
super("/myapp/facebook")
println "constructor"
}
#Override
public Authentication attemptAuthentication(HttpServletRequest arg0,
HttpServletResponse arg1) throws AuthenticationException,
IOException, ServletException {
println "attemptAuthentication"
return null;
}
then I go to
http://localhost:8080/myapp/facebook
Blank page and in console :
2014-09-26 18:09:57 [localhost].[/myapp] Initializing Spring FrameworkServlet 'grails-errorhandler'