disable swagger-ui based on roles - java

I am aware that swagger-ui can be fully disabled using #Profile on spring-boot application but I still want certain privileged user to be able to access swagger-ui and not fully disabled.
Is there a way to achieve this.
update:
currently I am using interceptor approach but i don't want this approach.
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if(request.getRequestURI().contains("swagger") &&
!request.isUserInRole("XX_YY_ZZ")) {
response.sendError(403, "You are not authorized to access "); }
return super.preHandle(request, response, handler);
}

Without version you use, or codes, it is difficult to help. But I'll try as best as I can.
When you are using swagger-ui, you have an exposed URL to access your docs (usually, /swagger-ui.html).
You are using spring-boot, and talking about user restriction, so I assume you can use spring-boot-starter-security.
With spring-boot-starter-security, you can configure easily what URL you want to protect (regarding user roles for instance).
Here is a sample configuration that works:
#Configuration
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// the rest of your configuration
http.authorizeRequests().mvcMatchers("/swagger-ui.html").hasRole("DEVELOPER")
}
You can secure swagger URLs just like any URLs you expose with your Controllers.
For more information:
A similar issue:
How to configure Spring Security to allow Swagger URL to be accessed without authentication
Spring security configuration:
https://spring.io/guides/gs/securing-web/
I could help more with:
An extract of your security configuration
The version of Spring-boot you're using

I would suggest adding an interceptor or you can handle it in your exiting interceptor if you have any.
In the spring configuration file:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/swager-url" />
<ref bean="swagerInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
<bean id="swagerInterceptor" class="com.security.SwagerInterceptor">
<property name="userService" ref="userService" />
</bean>
The interceptor class can be written similar to this:
public class SwagerInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//Take out user information from the request and validate
}

Related

Spring Security: How to get endpoint's authorities in Filter

In spring boot project I have a controller which has an endpoint with #PreAuthorize annotation
#RestController
#RequestMapping("/path")
class SomeController {
#PostMapping
#PreAuthorize("hasAuthority('SOME_AUTHORITY')")
public ResponseEntity<Object> doSomething() {
}
}
And also I have a filter that extends the OncePerRequestFilter
public class AuthTokenFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain f) throws IOException, ServletException {
//here I want to get the authorities specified in the controllers' endpoints
}
}
The question is how to get controllers' endpoints' authorities specified by the #PreAuthorize annotation in the above filter?
I recommend to move hasAuthority('SOME_AUTHORITY') into separate method in spring bean and use that method in filter and in #PreAuthorize annotation. In that way you will have common place for validate logic and you will keep code consistency as well.
Let me know if you need code examples.
You can do this in Spring Security's way, by using Pointcuts similar to AuthorizationMethodPointcuts. AuthorizationManagerBeforeMethodInterceptor reads these annotations using this pointcut.
GitHub link to spring-security for reference.
https://github.com/spring-projects/spring-security/tree/main/core/src/main/java/org/springframework/security/authorization
A filter dynamically intercepts requests and responses to transform or use the information contained in the requests or responses. Filters typically do not themselves create responses, but instead provide universal functions that can be "attached" to any endpoint.
OncePerRequestFilter . Spring guarantees that the OncePerRequestFilter is executed only once for a given request.
In your case you are extending OncePerRequestFilter in AuthTokenFilter and as you mentioned in comment you are authorizing user in this filter if user have valid details (in this case setting Authentication object).
Once you will hit your endpoint Spring will execute AuthTokenFilter logic
If details will valid then AuthTokenFilter will set Authentication in Spring context.
Spring Security supports authorization at the method level with help of different type of annotation like #PreAuthorize, #Secured . But enable annotation based security, we need to add the #EnableGlobalMethodSecurity annotation on any #Configuration class. example :
#Configuration
#EnableGlobalMethodSecurity(
prePostEnabled = true,
securedEnabled = true,
jsr250Enabled = true)
public class MethodSecurityConfiguration {
//default configuration class
}
HttpSecurity is tied to URL endpoints while #PreAuthorize is tied to controller methods and is actually located within the code adjacent to the controller definitions.
authorities/roles should set in Authentication object inside AuthTokenFilter (in your case) and those role can validated with #PreAuthorize annotation.
#PreAuthorize will trigger after AuthTokenFilter filter

Block HTTP 'TRACE' in Spring MVC with embedded Jetty server 7.5

I'm fairly new to spring security and I'm trying to disable the HTTP 'TRACE' method on my Spring webapp with Embedded Jetty server 7.5, but it doesn't seem to work. I tried a couple of ways based on questions asked on Stackoverflow, but still no luck.
here are my approaches:
Adding a Separate interceptor as suggested here:
My Context.xml looked like:
<interceptors>
<interceptor>
<mapping path="/**"/>
<beans:bean class="com.mypackage.HTTPMethodsInterceptor" />
</interceptor>
<interceptor>.... </interceptor>
</interceptors>
My Interceptor class:
public class HTTPMethodsInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if (!request.getMethod().equalsIgnoreCase("POST")
&& !request.getMethod().equalsIgnoreCase("GET")
&& !request.getMethod().equalsIgnoreCase("PUT")
&& !request.getMethod().equalsIgnoreCase("DELETE")) {
response.sendError(HttpServletResponse.SC_FORBIDDEN,
"Unauthorized Request");
return false;
} else {
return true;
}
}
}
This doesn't work even on my local. I tried debugging and putting a breakpoint interceptor class, but the breakpoint is not hit anytime.
Please let me know if I am doing something wrong or is there any correct way to implement this?
Thanks!

In memory and custom providers all together

I'm setting up my Spring Security (v4.0.1) web application. I want to have two authentication providers, an "in-memory" one to manage the administrator account and a custom one which refers to my own implementation. The system should attempt the authentication against the "in-memory" provider first of all and against the custom one in second place. My code looks like this:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
AuthenticationProvider provider) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin")
.password("s3cr3t")
.authorities("ADMIN");
auth.authenticationProvider(provider);
}
However, this code leads the framework to try my custom implementation first. It makes a bit of sense, since the AuthenticationManagerBuilder#authenticationProvider method adds a Provider to the internal List while the AuthenticationManagerBuilder#inMemoryAuthentication one configures it internally. How could I manage to get it work?
You can create your InMemoryUserDetailsManagerConfigurer manually and tell it to configure itself on the AuthenticationManagerBuilder when you have finished configuring it so it installs it's AuthenticationProvider before your custom one:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
AuthenticationProvider provider) throws Exception {
inMemoryConfigurer()
.withUser("admin")
.password("s3cr3t")
.authorities("ADMIN")
.and()
.configure(auth);
auth.authenticationProvider(provider);
}
private InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>
inMemoryConfigurer() {
return new InMemoryUserDetailsManagerConfigurer<>();
}
Normally what happens is that the InMemoryUserDetailsManagerConfigurer is created and added to the list of configurers that should be applied when the AuthenticationManager is built - which is after you've installed your custom AuthenticationProvider.
More or less from spring.io Documentation
If you are using XML configuration (e.g. spring-security.xml):
<security:authentication-manager>
<security:authentication-provider ref="FirstProvider" />
<security:authentication-provider ref="SecondProvider" />
</security:authentication-manager>
(I am using that setup for one of Spring's built-in authentication provider next to a custom one, works fine)
If you are using Java Config, I can only reference some other person's post maclema on Java config for multiple authentication provider, since I have never (successfully) tried code config
Today we tend to configure Spring Security via WebSecurityConfigurerAdapter, you register filters that extract credentials from a request and register providers that use tokens built by filters by populating Authentication object with other details like authorities:
#Override
protected void configure(HttpSecurity http) throws Exception {
AbstractPreAuthenticatedProcessingFilter tokenPreAuthProcessingFilter = new RequestHeaderAuthenticationFilter();
http.addFilterAfter(tokenPreAuthProcessingFilter, SecurityContextPersistenceFilter.class);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
// First.
auth.authenticationProvider(new PreAuthenticatedAuthenticationProvider());
// Second.
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser(...);
}

Spring Security: enable / disable CSRF by client type (browser / non-browser )

Spring Security documentation says:
"When you use CSRF protection? Our recommendation is to use CSRF
protection for any request that could be processed by a browser by
normal users. If you are only creating a service that is used by
non-browser clients, you will likely want to disable CSRF protection."
What if my service is going to be used by both "browser" and "non-browser" clients such as third party external services, does Spring Security provide a way to disable CSRF exclusively for certain type of clients?
I am sure there is a way to do this in Spring Security XML, but since I am using Java Config, here is my solution.
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Configuration
#Order(1)
public static class SoapApiConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/soap/**")
.csrf().disable()
.httpBasic();
}
}
#Configuration
public static class WebApiConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginProcessingUrl("/authentication")
.usernameParameter("j_username")
.passwordParameter("j_password").permitAll()
.and()
.csrf().disable()
}
}
}
IMHO, there is nothing like that out of the box. What I would do in your case, is to have a hierarchy of URL for example rooted at /api that would be exempt of csrf. It is easy to configure. In the XML config, you have a normal <http> block including <csrf/>, you just duplicate it and modify the first block like that
<http pattern="/api/**">
...
<!-- csrf -->
</http>
As it is first, it will be triggered for any request to /api hierachy without using csrf, and all other requests will use it.
In the normal part of the application, you never use the /api/** url, and reserve them to non-browser usages.
Then in your controllers, you map them to both their normal url and a copy under /api :
#Controller
#RequestMapping({ "/rootcontrollerurl", "/api/rootcontrollerurl"})
class XController {
#RequestMapping(value = "/request_part_url", ...)
public ModelAndView method() {
...
}
}
(of course, rootcontrollerurl and request_part_url may be blank ...)
But you must analyze the security implication of allowing non csrf controlled requests, and eventually exclude controllers from the /api hierarchy.
Here is what I used to disable the CSRF protection on an specific endpoint
on your appconfig-security.xml add a node with the information of your pattern like the following example:
<http security="none" pattern="/sku/*"/>
<http security="none" pattern="/sku/*/*"/>
<http security="none" pattern="/sku"/>
Just keep in mind the order is important if you are going to use map all request using the symbol '*' goes first.

AuthenticationSuccessHandler example for Spring Security 3

I am a newbie to Spring Security 3 . I am using roles for users to login.
I want to redirect a user to a different page based on the role of that user, I understand is that I would have to implement the AuthenticationSuccessHandler for the same, but some examples in that direction would help.
Thanks in advance,
Vivek
You can do something like this:
public class Test implements AuthenticationSuccessHandler {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
Set<String> roles = AuthorityUtils.authorityListToSet(authentication.getAuthorities());
if (roles.contains("ROLE_USER") {
response.sendRedirect("/userpage");
}
}
}
In the XML config add this:
<bean id="authenticationFilter" class="YOUR_AUTH_FILTER_HERE">
<!-- There might be more properties here, depending on your auth filter!! -->
<property name="authenticationSuccessHandler" ref="successHandler" />
</bean>
<bean id="successHandler" class="Test"/>

Categories

Resources