[GeoNode-devel] oauth2 - Issue managing layer access

Peter Marlow Peter.Marlow at scisys.co.uk
Thu Jan 4 07:36:23 PST 2018


Hi,

I'm trying to manage access to a layer through a combination of geonode, geofence and geoserver. So for example if a user does a GetCapabilities request for a WMS in geoserver they will only be shown layers which they have access to.

I've setup geonode, geoserver and geofence as described in this tutorial - http://docs.geonode.org/en/master/tutorials/admin/geoserver_geonode_security/

The link between geonode and geoserver appears to be working - that is to say that the geonode login button in geoserver works correctly and if I edit permissions for a layer in geonode then geofence is updated with the correct data rules.

The problem I encounter is when I do a request such as:

http://localhost/geoserver/geonode/wms?request=getcapabilities

via postman and provide basic authentication details (username/password) of a geonode user I get a 401 error returned and the following exception in the geoserver logs:

2018-01-04 15:16:05,659 DEBUG [security.IncludeQueryStringAntPathRequestMatcher] - Request matched by universal pattern '/**'
2018-01-04 15:16:05,659 DEBUG [security.IncludeQueryStringAntPathRequestMatcher] - Matched Path: /geonode/wms, QueryString: request=getcapabilities with /**
2018-01-04 15:16:05,659 DEBUG [geoserver.security] - AuthenticationCache has no entry for basic, testuser:f67c8204540f095070dd7a462cb44948
2018-01-04 15:16:05,660 DEBUG [geoserver.security] - Bad credentials
org.springframework.security.authentication.BadCredentialsException: Bad credentials
            at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:150)
            at org.geoserver.security.auth.UsernamePasswordAuthenticationProvider.authenticate(UsernamePasswordAuthenticationProvider.java:82)
            at org.geoserver.security.GeoServerAuthenticationProvider.authenticate(GeoServerAuthenticationProvider.java:58)
            at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
            at org.geoserver.security.GeoServerSecurityManager$1.authenticate(GeoServerSecurityManager.java:323)
            at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:178)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:73)
            at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:92)
            at org.geoserver.security.filter.GeoServerBasicAuthenticationFilter.doFilter(GeoServerBasicAuthenticationFilter.java:84)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:69)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.geoserver.security.filter.GeoServerSecurityContextPersistenceFilter$1.doFilter(GeoServerSecurityContextPersistenceFilter.java:53)
            at org.geoserver.security.filter.GeoServerCompositeFilter$NestedFilterChain.doFilter(GeoServerCompositeFilter.java:73)
            at org.geoserver.security.filter.GeoServerCompositeFilter.doFilter(GeoServerCompositeFilter.java:92)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.geoserver.security.GeoServerSecurityFilterChainProxy.doFilter(GeoServerSecurityFilterChainProxy.java:152)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
            at org.geoserver.filters.LoggingFilter.doFilter(LoggingFilter.java:87)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
            at org.geoserver.filters.GZIPFilter.doFilter(GZIPFilter.java:42)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
            at org.geoserver.filters.SessionDebugFilter.doFilter(SessionDebugFilter.java:48)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
            at org.geoserver.filters.FlushSafeFilter.doFilter(FlushSafeFilter.java:44)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
            at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
            at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
            at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
            at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
            at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1504)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1460)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:748)
2018-01-04 15:16:05,661 DEBUG [auth.GeoFenceAuthenticationProvider] - Auth request with org.springframework.security.authentication.UsernamePasswordAuthenticationToken at f33db8a7: Principal: testuser; Credentials: [PROTECTED]; Authenticated: false; Details: org.geoserver.security.filter.GeoServerWebAuthenticationDetails at 957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Not granted any authorities
2018-01-04 15:16:05,661 DEBUG [geofence.cache] - Loading user 'testuser'
2018-01-04 15:16:05,666 WARN [geofence.cache] - org.geoserver.geofence.cache.CachedRuleReader$NoAuthException: Can't auth user [testuser]
2018-01-04 15:16:05,670 INFO [auth.GeoFenceAuthenticationProvider] - User testuser NOT authenticated

Now I think this is because the filter chain for the /** is configured as:

basic
geonode-oauth2

So it is doing the first basic filter and failing because this checks against geoserver users and I provided a geonode user. My understanding of these filters is that upon failure it should progress to the next one, in this case the geonode-oauth2 filter which will call into geonode and authenticate the user. So my first question is why isn't that happening?

If I update the order of the default /** filter to place geonode-oauth2 first I get a capabilities document returned but it does not contain the layer that I have granted access to for the geonode user, the geoserver logs show the following:

2018-01-04 15:21:52,163 DEBUG [security.IncludeQueryStringAntPathRequestMatcher] - Request matched by universal pattern '/**'
2018-01-04 15:21:52,163 DEBUG [security.IncludeQueryStringAntPathRequestMatcher] - Matched Path: /geonode/wms, QueryString: request=getcapabilities with /**
2018-01-04 15:21:52,226 DEBUG [geoserver.security] - Inspecting the http request looking for the GeoNode Session ID.
2018-01-04 15:21:52,226 DEBUG [geoserver.security] - Found no cookies!
2018-01-04 15:21:52,226 DEBUG [geoserver.security] - preAuthenticatedPrincipal = null, trying to authenticate
2018-01-04 15:21:52,227 DEBUG [geoserver.geofence] - Getting access limits for workspace geonode
2018-01-04 15:21:52,227 DEBUG [geoserver.geofence] - Getting admin auth for Workspace geonode
2018-01-04 15:21:52,227 DEBUG [geoserver.geofence] - AdminAuth filter: RuleFilter[user:(empty)+ role:ANY inst:name+:default-gs ip:"10.0.2.2"+ serv:ANY req:ANY ws:"geonode"+ layer:ANY]
2018-01-04 15:21:52,227 DEBUG [geofence.cache] - AdminAuth Request for RuleFilter[user:(empty)+ role:ANY inst:name+:default-gs ip:"10.0.2.2"+ serv:ANY req:ANY ws:"geonode"+ layer:ANY]
2018-01-04 15:21:52,228 DEBUG [geofence.cache] - Loading RuleFilter[user:(empty)+ role:ANY inst:name+:default-gs ip:"10.0.2.2"+ serv:ANY req:ANY ws:"geonode"+ layer:ANY]
2018-01-04 15:21:52,228 DEBUG [geofence.internal] - Getting Roles for User []
2018-01-04 15:21:52,228 DEBUG [geofence.internal] - Checking UserGroupService [default]
2018-01-04 15:21:52,228 DEBUG [geofence.internal] - Checking RoleService [default]
2018-01-04 15:21:52,228 DEBUG [geofence.internal] - Checking RoleService [geonode REST role service]
2018-01-04 15:21:52,319 DEBUG [geoserver.security] - Setting ROLES for User [] to [ROLE_ANONYMOUS]
2018-01-04 15:21:52,392 DEBUG [geoserver.security] - Setting ROLES for User [] to [ROLE_ANONYMOUS]
2018-01-04 15:21:52,392 DEBUG [geofence.internal] - RoleService [geonode REST role service] matching for User []
2018-01-04 15:21:52,446 DEBUG [geoserver.security] - Setting ROLES for User [] to [ROLE_ANONYMOUS]
2018-01-04 15:21:52,447 DEBUG [geofence.internal] - Checking Role [ROLE_ANONYMOUS] on ActiveRoleService [org.geoserver.security.GeoServerRestRoleService at 1491bfb5]
2018-01-04 15:21:52,447 DEBUG [geofence.internal] - Checking UserGroupService [default]
2018-01-04 15:21:52,447 DEBUG [geofence.internal] - Matching Roles [[ROLE_ANONYMOUS]] for User []
2018-01-04 15:21:52,494 DEBUG [geoserver.security] - Setting ROLES for User [] to [ROLE_ANONYMOUS]
2018-01-04 15:21:52,494 DEBUG [geofence.internal] - Checking Role [ROLE_ANONYMOUS] on ActiveRoleService [org.geoserver.security.GeoServerRestRoleService at 1491bfb5]
2018-01-04 15:21:52,494 DEBUG [geofence.internal] - Checking UserGroupService [default]
2018-01-04 15:21:52,494 DEBUG [geofence.internal] - Matching Roles [[ROLE_ANONYMOUS]] for User []
2018-01-04 15:21:52,495 DEBUG [geoserver.geofence] - Admin auth for User: Workspace:geonode: false

I think the above is showing that the user failed authentication because the RuleFilter for geofence is being passed an empty username, which is why the layer isn't being shown.

My second question is why didn't the authentication process throw any errors? I've taken a look at the GeoServerOAuthAuthenticationFilter class (https://github.com/geoserver/geoserver/blob/master/src/community/security/oauth2/src/main/java/org/geoserver/security/oauth2/GeoServerOAuthAuthenticationFilter.java) and I wonder whether when it calls this line:

authentication = filter.attemptAuthentication(req, null);

it is swallowing any IOException or ServletException that are thrown by the base Spring class?


I'm also wondering whether I've just misunderstood how the security between geonode and geoserver should work. My high-level view is that when a geonode user requests to access a resource directly via geoserver (for example a WMS service) then geoserver will call into geonode to check that the user is valid, retrieve the users' roles and then pass these to geofence which will check the data rules to ensure the user has access to the targeted resource.

Thanks,
Pete



SCISYS UK Limited. Registered in England and Wales No. 4373530.
Registered Office: Methuen Park, Chippenham, Wiltshire SN14 0GB, UK.
 
Before printing, please think about the environment.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/geonode-devel/attachments/20180104/00ac293f/attachment-0001.html>


More information about the geonode-devel mailing list