<commit_before>package org.oasis.datacore.core.security.mock;

import java.util.ArrayList;
import java.util.Set;

import org.oasis.datacore.core.security.DCUserImpl;
import org.oasis.datacore.core.security.oauth2.RemoteUserAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;

/**
 * Mock local auth service using default hardcoded user conf.
 * 
 * TODO migrate / merge to custom AuthenticationProvider (?) that returns well-filled
 * OIDCAuthenticationToken
 * http://aykutakin.wordpress.com/2013/07/08/spring-security-spring-custom-authentication-provider/
 * 
 * ALL AUTHENTICATION SERVICES / PROVIDER should provide users :
 * - guest with guest authority (modeled as (Datacore-wide) default group) TODO OR use AnonymousAuthenticationToken ?
 * - all other users with additional guest authority (add it on load if not yet there)
 * - "admin" user ; TODO users are made admin by conf (hardcoded and LATER REST API)
 * 
 * @author mdutoo
 *
 */
@Component // always instanciated but non-test code can't call it
public class MockAuthenticationService {
	
   /** User id (for resource auditor & creator as owner) in case there is no Spring Security
    * Authentication object in context (even guest or system should have one). Can only
    * happen if EntityServiceImpl is used directly and not through its secured interface. */
   public static final String NO_USER = "*no_user*";
   
   /** TODO LATER remove optional when there is a mock in the -core project */
   @Autowired(required = false)
   @Qualifier("datacore.userDetailsService")
   private UserDetailsService mockUserDetailsService;
   
   public void loginAs(String username) {
      UserDetails userDetails = mockUserDetailsService.loadUserByUsername(username);
      if (userDetails == null) {
         SecurityContextHolder.clearContext();
         throw new RuntimeException("Unknown user " + username);
      }
      
      DCUserImpl user = new DCUserImpl((User) userDetails); // NB. also precomputes its permissions 
      
      Authentication authentication = new TestingAuthenticationToken(user, "",
            new ArrayList<GrantedAuthority>(userDetails.getAuthorities()));
      // TODO rather than PreAuthenticatedAuthenticationToken because mock <commit_msg>auth mock : added doc & TODO<commit_after>package org.oasis.datacore.core.security.mock;

import java.util.ArrayList;
import java.util.Set;

import org.oasis.datacore.core.security.DCUserImpl;
import org.oasis.datacore.core.security.oauth2.RemoteUserAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;

/**
 * Mock local auth service using default hardcoded user conf, available in dev mode only.
 * 
 * TODO separate what is mock (loginAs) from what is not (getCurrentUser(Id)/EntityGroups())
 * 
 * Hardcoded conf should provide users :
 * - "guest" with guest authority (modeled as (Datacore-wide) default group)
 * - all other users with additional guest authority (add it on load if not yet there)
 * - "admin" user ; TODO users are made admin by conf (hardcoded and LATER REST API)
 * 
 * @author mdutoo
 *
 */
@Component // always instanciated but non-test code can't call it
public class MockAuthenticationService {
	
   /** User id (for resource auditor & creator as owner) in case there is no Spring Security
    * Authentication object in context (even guest or system should have one). Can only
    * happen if EntityServiceImpl is used directly and not through its secured interface. */
   public static final String NO_USER = "*no_user*";
   
   /** TODO LATER remove optional when there is a mock in the -core project */
   @Autowired(required = false)
   @Qualifier("datacore.userDetailsService")
   private UserDetailsService mockUserDetailsService;
   
   /**
    * WARNING can only log in a mock auth hardcoded conf user, not ex. an OAuth user
    * (because it would have to get its details) 
    * @param username
    */
   public void loginAs(String username) {
      UserDetails userDetails = mockUserDetailsService.loadUserByUsername(username);
      if (userDetails == null) {
         SecurityContextHolder.clearContext();
         throw new RuntimeException("Unknown user " + username);
      }
      
      DCUserImpl user = new DCUserImpl((User) userDetails); // NB. also precomputes its permissions 
      
      Authentication authentication = new TestingAuthenticationToken(user, "",
            new ArrayList<GrantedAuthority>(userDetails.getAuthorities()));
      // TODO rather than PreAuthenticatedAuthenticationToken because mock 
{'fraction_non_alphanumeric': 0.08266753627914561, 'fraction_numerical': 0.0022827327572150662, 'mean_word_length': 4.576363636363636, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5222752', 'n_tokens_mistral': 1575, 'n_tokens_neox': 1534, 'n_words': 473}