ataylor284 / spring-security-eventlog

A grails plugin to log spring security events.
5 stars 7 forks source link

spring security authorizations logging #4

Open kmacpher67 opened 10 years ago

kmacpher67 commented 10 years ago

The samples seem mostly authentication oriented. Is there security event native fired when a user attempts an unauthorized resource /reallyImportant [ROLE_ADMIN] but a regular user attempts to access /reallyImportant and gets the authorization exception. "Sorry, you're not authorized to view this page."

My experience is that Spring Security is pretty lacking the "reason" as the voters context is basically lost. But can we atleast catch the basic "AccessDeniedException" ?

[bio-8080-exec-5] DEBUG - ess.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /secure/important; Attributes: [ROLE_ADMIN] [bio-8080-exec-5] DEBUG - ess.intercept.FilterSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@ffa9ccdf: Principal: grails.plugin.springsecurity.userdetails.GrailsUser@bbb4975d: Username: testuser; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@59b2: RemoteIpAddress: 10.0.8.162; SessionId: null; Granted Authorities: ROLE_USER [bio-8080-exec-5] DEBUG - ess.hierarchicalroles.RoleHierarchyImpl - getReachableGrantedAuthorities() - From the roles [ROLE_USER] one can reach [ROLE_USER] in zero or more steps. [bio-8080-exec-5] DEBUG - y.web.access.ExceptionTranslationFilter - Access is denied (user is not anonymous); delegating to AccessDeniedHandler org.springframework.security.access.AccessDeniedException: Access is denied at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.deny(AuthenticatedVetoableDecisionManager.java:113) at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.checkOtherVoters(AuthenticatedVetoableDecisionManager.java:105) at grails.plugin.springsecurity.access.vote.AuthenticatedVetoableDecisionManager.decide(AuthenticatedVetoableDecisionManager.java:44) at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53) at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49) at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) at java.lang.Thread.run(Thread.java:662)

ataylor284 commented 10 years ago

It looks like spring security fires notifications on authorization events similar to how it handles authentications. It should be fairly easy to extend the plugin to log these as well. They might not fit into the existing table very well though. I wonder if it makes sense to have two tables, one for authorizations and one for authentications.

ataylor284 commented 10 years ago

Here's a pointer to the event class: http://docs.spring.io/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/access/event/AbstractAuthorizationEvent.html

kmacpher67 commented 10 years ago

I was thinking it would be good to have Granted Authorities (authorities) column to track the user's current roles and maybe a extra custom stuff/messages column in the domain object (which could be used for authorization extras), the WebAuthenticationDetails has a custom method for some other goodies: doPopulateAdditionalInformation.

kmacpher67 commented 10 years ago

AuthorizationFailureEvent is constructed using: (Object secureObject, Collection attributes, Authentication authentication, AccessDeniedException accessDeniedException) The AccessDeniedException(String msg) returned is simply "Access is denied" that we see in the logs above, that could be mapped to the domain attribute: eventName.
The only missing is the extras like: GrantedAuthorities (which would be nice to have in Authentication cause we have dynamic GA based on user's current active profile).
getConfigAttributes() will get representation of the configuration attribute data like url, privs, that AccessDecisionManager used to evaluate or vote for the event (maybe we want to log these goodies, but maybe that's an extra stuff column or as Spring calls it "AdditionalInformation" ). So I wrote a new class, but used the same table to write the data to.

class SpringSecurityAuthZAuditLogger  extends LoggerListener{
    void onApplicationEvent(AbstractAuthorizationEvent event){
        log.debug(" onApplicationEvent " + event)
logAuthenticationEvent(event.getAccessDeniedException().getMessage(), event.authentication, event.authentication?.details?.remoteAddress, event.authentication.principal?.authorities.toString())
    }
Note: I put the authorties into switchedUsername just for brevity sake. 
kmacpher67 commented 10 years ago

Pretty cool, just goes right in there, like it was meant to, your call on a new domain object/table. IMHO you could use the existing one it's just another security event message like logout.

15  2014-01-22 14:37:13.948 Access is denied    10.0.8.162  62C501C31F5F7ACC012C5A25018E18B1    [ROLE_USER] testuser
16  2014-01-22 14:39:59.482 Access is denied    127.0.0.1   null    [ROLE_ANONYMOUS]    __grails.anonymous.user__
17  2014-01-22 14:40:05.754 Access is denied    127.0.0.1   BA6D4CB12A931067BCE28CDC0A7A5942    [ROLE_ANONYMOUS]    __grails.anonymous.user__