audit4j / audit4j-core

An open source auditing framework.
http://audit4j.org
Apache License 2.0
126 stars 76 forks source link

Spring security integration #15

Closed bianghouse closed 8 years ago

bianghouse commented 8 years ago

Hi, is there a way to join Spring security Authentication? There is an example inside doc about MetaData Customization where you place an implementation example import org.audit4j.core.MetaData; public class MyMetaData implements MetaData{ @Override public String getActor() { return MyContext.getAuthanticatedUSer(); } } so I tried to retrieve my spring authentication user from SecurityContext, but it returns always null authentication even if user is already logged in.

Could You please show me how to retrive a filled value from "MyContext.getAuthanticatedUSer()"?

janithb commented 8 years ago

Can you please share your metadata implementation. Then I'll be able to resolve this.

bianghouse commented 8 years ago

Hi Janith, first of all, thanks a lot for your great job!

Below my implementation of your MetaData interface

public class AuditMetaData implements MetaData, Serializable { ..... @Override public String getActor() {

    SecurityContext context = SecurityContextHolder.getContext();
    Authentication auth = context.getAuthentication(); <= this is always null after user successful authenticated
    UserSessionBean user = (UserSessionBean) auth.getPrincipal();
    return user.getUsername();
}

}

and my

UserAuthenticationService implements UserDetailsService { @Transactional(readOnly = true) @Override public UserSessionBean loadUserByUsername(final String userName) throws UsernameNotFoundException { .... return buildUserForAuthentication(user, authorities); }

private UserSessionBean buildUserForAuthentication(User user, List authorities) { .... if(passwordEncoder.matches(credential, userBean.getPassword())) {

        Authentication token = new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), authorities);
        SecurityContextHolder.getContext().setAuthentication(token);
        userBean.setAuthenticated(true);
        fillUserData(user);
    }
    else
    {
        userBean.setAuthenticated(false);
    }

    return userBean;
}

}

janithb commented 8 years ago

Hi,

We are using spring security with large enterprise application and its working fine.

Follow is the custom metadata implementation code I picked from that application.

  public String getActor() {
    final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

    if (authentication == null) {
      return ANONYMOUS_USER_LAN_ID;
    }

    final Object principal = authentication.getPrincipal();

    if (principal instanceof CurrentUser) {
      return ((CurrentUser) principal).getUsername();
    } else if (principal instanceof String && ANONYMOUS_USER_LAN_ID.equals(principal)) {
      return ANONYMOUS_USER_LAN_ID;
    } else {
      throw new IllegalStateException("Unrecognized principal while getting the current user: " + principal);
    }
  }

Can you please mention what Audit4j core version you are using.

Can you please verify whether application is properly authenticated.

Regards, Janith

bianghouse commented 8 years ago

Hi Janith, thanks for sharing your implementation.. It seems like mine and they are bases on the same key SecurityContextHolder.getContext().getAuthentication() anyway.

I tried both Audit4j-core v 2.3.1, 2.4.0 alpha versions, but I don't think this is the issue.

I think there's something wrong on my application configuration, because as soon as code invokes my custom implementation of Metadata (getActor method), the SecurityContextHolder looses its references to the to the whole application context, but I can confirm that application is properly authenticated.

I have two distinct webfilters, one for web authentication, one for rest-mobile authentication and they both work as espected. So I have to deeply investigate to find the reason of the issue.

follow how I configured audit4j spring beans

Configuration
@EnableWebMvc
@EnableAspectJAutoProxy
@EnableTransactionManagement
@ComponentScan(basePackages =
{ "....", "...." }, excludeFilters =
{
 @ComponentScan.Filter(type = FilterType.CUSTOM, value =
 ....),
})
public class WebConfig extends WebMvcConfigurerAdapter implements Serializable
{
.....
@Bean
    public AuditAspect auditAspect()
    {
        AuditAspect auditAspect = new AuditAspect();
        return auditAspect;
    }

    @Bean
        public SpringAudit4jConfig springAudit4jConfig() {
            SpringAudit4jConfig springAudit4jConfig = new SpringAudit4jConfig();
            springAudit4jConfig.setLayout(new SimpleLayout());
            List<Handler> handlers = new ArrayList<Handler>();
            handlers.add(new ConsoleAuditHandler());
            DatabaseAuditHandler dbHandler = new DatabaseAuditHandler();
            dbHandler.setEmbedded("false");
            dbHandler.setDb_connection_type("jndi");
            dbHandler.setDb_jndi_datasource("java:jboss/datasources/DS");
            handlers.add(dbHandler);
            springAudit4jConfig.setHandlers(handlers);
            springAudit4jConfig.setMetaData(new AuditMetaData());
            return springAudit4jConfig;
        }

}

thank you for your willingness. Regards, Marco.

janithb commented 8 years ago

Marked this as a bug since asynchronous metadata lookup is not working for spring security with annotations. Fixed issue in audit4j-core-2.4.0-alpha3. Please use this version until release a stable release.

janithb commented 8 years ago

audit4j-core-2.4.0-alpha3 is available in mevan central. closing issue.

janzyka commented 7 years ago

For any future visitors, the root cause is that spring stores authentication in ThredLocal and Audit4j was processing the events in separate thread which didn't see the ThreadLocal which is local to the web request thread.

The new version fixed that by running the metadata retrieval from the source thread.