I am trying to secure the Spring Boot actuactor endpoints. I have working security on my /api REST interface, but trying to add security on the built-in endpoints does not seem to work.
I have set up grouping of the endpoints in my application.properties:
management.context-path=/management
I have this in my Java Config
#Override
protected void configure( HttpSecurity http ) throws Exception
{
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS );
http.authorizeRequests()
.antMatchers( "/api/**" ).hasRole( "READONLY" )
.antMatchers( "/management/**" ).hasRole( "ADMIN" );
SecurityConfigurer<DefaultSecurityFilterChain, HttpSecurity> securityConfigurer = new XAuthTokenConfigurer( userDetailsServiceBean() );
http.apply( securityConfigurer );
}
When I use my browser to go to anything below /api, I get a 403 back as expected. When going to /management/info for example, I see the JSON being returned where I would also expect a 403.
I also tried adding this to my application.properties file:
management.security.role=ADMIN
But that did not help either.
The DEBUG output shows:
2014-05-02 10:15:30 DEBUG [localhost-startStop-1] ExpressionBasedFilterInvocationSecurityMetadataSource -
Adding web access control expression 'hasRole('ROLE_READONLY')', for Ant [pattern='/api/**']
2014-05-02 10:15:30 DEBUG [localhost-startStop-1] ExpressionBasedFilterInvocationSecurityMetadataSource -
Adding web access control expression 'hasRole('ROLE_ADMIN')', for Ant [pattern='/management/**']
And then why I try the HTTP GET:
2014-05-02 10:16:39 DEBUG [http-nio-8443-exec-4] AntPathRequestMatcher - Checking match of request : '/management/info'; against '/css/**'
2014-05-02 10:16:39 DEBUG [http-nio-8443-exec-4] AntPathRequestMatcher - Checking match of request : '/management/info'; against '/js/**'
2014-05-02 10:16:39 DEBUG [http-nio-8443-exec-4] AntPathRequestMatcher - Checking match of request : '/management/info'; against '/images/**'
2014-05-02 10:16:39 DEBUG [http-nio-8443-exec-4] AntPathRequestMatcher - Checking match of request : '/management/info'; against '/**/favicon.ico'
2014-05-02 10:16:39 DEBUG [http-nio-8443-exec-4] AntPathRequestMatcher - Checking match of request : '/management/info'; against '/management/info'
2014-05-02 10:16:39 DEBUG [http-nio-8443-exec-4] FilterChainProxy - /management/info has an empty filter list
The log that tells the story is: "/management/info has an empty filter list" because it is explicitly marked as ignored (/info is always supposed to be available). Try one of the other actuator endpoints and see if those behave as you expect. If you really need to secure the info endpoint you can set endpoints.info.sensitive=true (I think).
Related
This is a bit annoying since I've solved the original problem (which was this) but now this is another thing that I can't quite debug myself.
I am using JHispter 6.10 (Spring Boot 2.2.7.RELEASE) + React for my project. I've recently come to the need of using entities as catalogues (so they can be managed easily by an admin) and they need to be used on the register page. My first problem was that they wouldn't the dropdown in the register page, but that problem had to do with SecurityConfiguration.java, so I added the entities to be permitted to All:
.antMatchers("/api/comunidad-famdals").permitAll()
.antMatchers("/api/ciudads").permitAll()
.antMatchers("/api/estados").permitAll()
.antMatchers("/api/ladrillo-famdals").permitAll()
.antMatchers("/api/pais").permitAll()
.antMatchers("/api/**").authenticated()
And that seems to work just fine, but the first time I load the app (in dev mode), it throws the next error:
2020-10-09 02:03:33.337 DEBUG 63312 --- [ XNIO-1 task-9] c.f.m.r.CustomAuditEventRepository : Enter: add() with argument[s] = [AuditEvent [timestamp=2020-10-09T07:03:33.302498Z, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={details=org.springframework.security.web.authentication.WebAuthenticationDetails#b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null, type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]]
2020-10-09 02:03:33.342 DEBUG 63312 --- [ XNIO-1 task-9] c.f.m.r.CustomAuditEventRepository : Exit: add() with result = null
2020-10-09 02:03:33.473 WARN 63312 --- [ XNIO-1 task-9] o.z.problem.spring.common.AdviceTraits : Unauthorized: Full authentication is required to access this resource
2020-10-09 02:03:33.564 WARN 63312 --- [ XNIO-1 task-9] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource]
And when trying to register, the dropdown still doesn't show anything:
But if I go home once again, the terminal shows that all the queries have been done correctly, and sure enough, if I go back to the register page:
I would like to know if I am missing something on my SecurityConfiguration.java or if the order of the configuration needs to be different for it to work properly.
you have to give permissions to your endpoint in the Spring Boot Configuration (SecurityConfiguration.java)
add a new antMatchers parameter to the HttpSecurity.authorizeRequests() it should look like this:
http
.authorizeRequests()
.antMatchers("/api/yourEndpoint").permitAll()
of course you have to select who has authority to call this endpoint
Hope it works for you :)
I am trying to connect a Spring application to an AD-LDAP server. If I type the correct user/pass-data I get NO_OBJECT-error in the log:
DEBUG o.s.s.l.s.FilterBasedLdapUserSearch - Searching for user 'THEUSER', with user search [ searchFilter: '(sAMAccountName={0})', searchBase: 'DC=dev,DC=company,DC=local', scope: subtree, searchTimeLimit: 0, derefLinkFlag: false ]
DEBUG o.s.s.l.SpringSecurityLdapTemplate - Searching for entry under DN '', base = 'dc=entwicklung,dc=Lemken,dc=local', filter = '(sAMAccountName={0})'
DEBUG o.s.s.l.SpringSecurityLdapTemplate - Found DN: CN=THEUSER\, FirstName,OU=users,DC=dev,DC=company,DC=local
DEBUG o.s.s.l.a.BindAuthenticator - Attempting to bind as cn=THEUSER\, FirstName,ou=users,dc=dev,dc=company,dc=local
DEBUG o.s.s.l.DefaultSpringSecurityContextSource - Removing pooling flag for user cn=THEUSER\, FirstName,ou=users,dc=dev,dc=company,dc=local
DEBUG o.s.s.l.u.DefaultLdapAuthoritiesPopulator - Getting authorities for user cn=THEUSER\, FirstName,ou=users,dc=dev,dc=company,dc=local
DEBUG o.s.s.l.u.DefaultLdapAuthoritiesPopulator - Searching for roles for user 'THEUSER', DN = 'cn=THEUSER\, FirstName,ou=users,dc=dev,dc=company,dc=local', with filter (uniqueMember={0}) in search base ''
DEBUG o.s.s.l.SpringSecurityLdapTemplate - Using filter: (uniqueMember=cn=THEUSER\5c, FirstName,ou=users,dc=dev,dc=company,dc=local)
ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
org.springframework.ldap.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-03100213, problem 2001 (NO_OBJECT), data 0, best match of:
''
This is my configuration:
ContextSourceBuilder context = auth.ldapAuthentication()
.userSearchFilter("(sAMAccountName={0})")
.userSearchBase("dc=dev,dc=company,dc=local")
.contextSource();
context.port(389);
context
.root("dc=dev,dc=company,dc=local")
.url("ldap://example.com")
.managerDn("cn=manager,ou=users,dc=dev,dc=company,dc=local")
.managerPassword("thepassword");
If i type a wrong password I get "Bad password", so this part works.
What am I doing wrong?
The key parts are:
Searching for roles
...
Using filter: (uniqueMember=
It is trying to find the user's roles - in AD those are the groups that the user is a member of. But it's doing that by searching groups that have the uniqueMember attribute set to the user. That attribute doesn't exist in AD. That is the default attribute name it uses since that's what's used in OpenLDAP.
You will need to use groupSearchFilter() to change the attribute it looks at to find groups. AD uses the member attribute.
ContextSourceBuilder context = auth.ldapAuthentication()
.userSearchFilter("(sAMAccountName={0})")
.userSearchBase("dc=dev,dc=company,dc=local")
.groupSearchFilter("(member={0})")
.contextSource();
I'm trying to implement HTML5 routing with Spring-boot and Angular 1.5, following this article.
At some point I need to redirect all the angular routes to the base path with a controller like this:
#Controller
public class UrlController {
// Match everything without a suffix (so not a static resource)
#RequestMapping(value = "/{path:[^\\.]*}"))
public String redirect(HttpServletRequest request) {
// Forward to home page so that route is preserved.
return "forward:/";
}
}
While the regular expression matches most of the URLS, like dashboard, search etc:
2016-08-05 16:39:58 DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping:306 - Looking up handler method for path /dashboard
2016-08-05 16:39:58 DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping:313 - Returning handler method UrlController.redirect(javax.servlet.http.HttpServletRequest,java.lang.String)]
2016-08-05 16:39:58 DEBUG o.s.b.f.s.DefaultListableBeanFactory:251 - Returning cached instance of singleton bean 'urlController'
2016-08-05 16:39:58 DEBUG o.s.w.s.DispatcherServlet:947 - Last-Modified value for [/dashboard] is: -1
2016-08-05 16:39:58 DEBUG c.a.a.w.i.LoggingInterceptor:22 - Start processing url request: https://localhost:8443/dashboard
redirecting to home page from url https://localhost:8443/dashboard
2016-08-05 16:39:58 DEBUG c.a.a.w.i.LoggingInterceptor:35 - Finished processing url request: https://localhost:8443/dashboard, duration: 0[ms]
Others are ignored and not matched at all, like https://localhost:8443/faults/64539352
2016-08-05 17:00:05 DEBUG o.s.w.s.DispatcherServlet:861 - DispatcherServlet with name 'dispatcherServlet' processing GET request for [/faults/64539352]
2016-08-05 17:00:05 DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping:306 - Looking up handler method for path /faults/64539352
2016-08-05 17:00:05 DEBUG o.s.w.s.m.m.a.RequestMappingHandlerMapping:316 - Did not find handler method for [/faults/64539352]
The regular expression seems to be fine if you test it in regexplanet
, but it does not match what I want if I put it in the #RequestMapping.
Does anybody know how to make it work, or even better how to do it without regular expressions?
The problem and solution is described here. The solution consist in the implementation of a OncePerRequestFilter where you can match the full URI against whatever you want.
You can use a correct PathMatcher to do the job: {path:(?:(?!api|.).)*}/**
More info here
I am trying this example to get the profile of a LinkedIn user using Spring Social. The source code of the project is also available here
The user gets redirected to the LinkedIn authorization page https://www.linkedin.com/uas/oauth/authorize?oauth_token=* and the user allows the app access to his profile. After the user clicks on the button "Allow Access", he gets redirected to http://localhost:7090/spring-oauth-linkedin-sample/connect/linkedin?oauth_token=*&oauth_verifier=*** and here the exception is thrown:
HTTP ERROR 500
Problem accessing /spring-oauth-linkedin-sample/connect/linkedin. Reason:
Server Error
Caused by:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException: 403 Forbidden
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:656)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:751)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1666)
In the eclipse console I get:
DEBUG - 7568555-17 - RestTemplate - Created POST request for "https://api.linkedin.com/uas/oauth/accessToken"
DEBUG - 7568555-17 - RestTemplate - Setting request Accept header to [text/plain, */*]
DEBUG - 7568555-17 - RestTemplate - Writing [{}] using [org.springframework.http.converter.FormHttpMessageConverter#5eedaba0]
DEBUG - 7568555-17 - RestTemplate - POST request for "https://api.linkedin.com/uas/oauth/accessToken" resulted in 200 (OK)
DEBUG - 7568555-17 - RestTemplate - Reading [java.lang.String] as "text/plain" using [org.springframework.http.converter.StringHttpMessageConverter#7e8b6c76]
DEBUG - 7568555-17 - RestTemplate - Created GET request for "https://api.linkedin.com/v1/people/~:public"
DEBUG - 7568555-17 - RestTemplate - Setting request Accept header to [application/xml, text/xml, application/*+xml, application/json]
WARN - 7568555-17 - RestTemplate - GET request for "https://api.linkedin.com/v1/people/~:public" resulted in 403 (Forbidden); invoking error handler
DEBUG - 7568555-17 - odHandlerExceptionResolver - Resolving exception from handler [org.springframework.social.web.connect.ConnectController#1c178a81]: org.springframework.web.client.HttpClientErrorException: 403 Forbidden
DEBUG - 7568555-17 - nseStatusExceptionResolver - Resolving exception from handler [org.springframework.social.web.connect.ConnectController#1c178a81]: org.springframework.web.client.HttpClientErrorException: 403 Forbidden
DEBUG - 7568555-17 - ltHandlerExceptionResolver - Resolving exception from handler [org.springframework.social.web.connect.ConnectController#1c178a81]: org.springframework.web.client.HttpClientErrorException: 403 Forbidden
DEBUG - 7568555-17 - DispatcherServlet - Could not complete request
org.springframework.web.client.HttpClientErrorException: 403 Forbidden
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:75)
at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:486)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:443)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:199)
at org.springframework.social.linkedin.LinkedInTemplate.getUserProfile(LinkedInTemplate.java:56)
at org.springframework.social.linkedin.LinkedInTemplate.getProfileId(LinkedInTemplate.java:48)
at org.springframework.social.linkedin.connect.LinkedInServiceProvider.getProviderAccountId(LinkedInServiceProvider.java:44)
at org.springframework.social.linkedin.connect.LinkedInServiceProvider.getProviderAccountId(LinkedInServiceProvider.java:28)
at org.springframework.social.connect.oauth1.AbstractOAuth1ServiceProvider.connect(AbstractOAuth1ServiceProvider.java:51)
at org.springframework.social.web.connect.ConnectController.oauth1Callback(ConnectController.java:147)
I have a resource server and an auth server.
On resource request it verifies the received access_token with the auth server on a /oauth/check_token endpoint. This gives a response that makes my request crash.
The response is sent as:
Written [{exp=1433335640, scope=[read, write], authorities=[ROLE_USER], client_id=client-w-s}] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#58a88f5a]
When my resource server receives it:
2015-06-03 14:17:48.277 DEBUG 9492 --- [nio-8181-exec-3] o.s.web.client.RestTemplate : POST request for "http://localhost:6707/oauth/check_token" resulted in 200 (OK)
2015-06-03 14:17:48.277 DEBUG 9492 --- [nio-8181-exec-3] o.s.web.client.RestTemplate : Reading [interface java.util.Map] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#67409450]
2015-06-03 14:17:48.283 ERROR 9492 --- [nio-8181-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
java.lang.ArrayStoreException: null
at java.util.ArrayList.toArray(Unknown Source)
at org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter.extractAuthentication(DefaultAccessTokenConverter.java:139)
This is the piece of code it fails on:
Collection<? extends GrantedAuthority> authorities = null;
if (user==null && map.containsKey(AUTHORITIES)) {
#SuppressWarnings("unchecked")
String[] roles = ((Collection<String>)map.get(AUTHORITIES)).toArray(new String[0]);
authorities = AuthorityUtils.createAuthorityList(roles);
}
I ran in debug mode to check the values in map, and everything looks like I think it should judging from the response my auth server built.
Please tell me if I need to post more information.
Has anyone experienced this or have any clue on how to solve it?
I found the "solution".
There was a version mismatch in my pom files. While my auth server was running spring-security-oauth2-2.0.5.RELEASE my resource server was running spring-security-oauth2-2.0.7.RELEASE .
The versions declare the response differently.
I think there is an error in DefaultAccessTokenConverter implementation, since spring-security-oauth2 2.0.7.RELEASE, because of this line:
if (user==null && map.containsKey(AUTHORITIES)) {
...
}
Why the "user==null" condition?
The "user" variable isn't null, so the condition is never true, and the authorities array is not filled.
I think this is a Spring Security Oauth2 implementation error.