WildflyApplicationAuthenticationProvider.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */

  20. package org.openspcoop2.utils.service.authentication.provider;

  21. import java.io.File;
  22. import java.io.FileInputStream;
  23. import java.security.MessageDigest;
  24. import java.util.ArrayList;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.Properties;

  28. import org.openspcoop2.utils.UtilsException;
  29. import org.openspcoop2.utils.io.Base64Utilities;
  30. import org.openspcoop2.utils.io.HexBinaryUtilities;
  31. import org.slf4j.Logger;
  32. import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
  33. import org.springframework.security.authentication.AuthenticationProvider;
  34. import org.springframework.security.authentication.AuthenticationServiceException;
  35. import org.springframework.security.authentication.BadCredentialsException;
  36. import org.springframework.security.authentication.ProviderNotFoundException;
  37. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  38. import org.springframework.security.core.Authentication;
  39. import org.springframework.security.core.AuthenticationException;
  40. import org.springframework.security.core.GrantedAuthority;
  41. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  42. import org.springframework.security.core.userdetails.User;
  43. import org.springframework.security.core.userdetails.UserDetails;
  44. import org.springframework.security.core.userdetails.UsernameNotFoundException;
  45. import org.springframework.security.core.userdetails.UserDetailsService;


  46. /**
  47.  * WildflyApplicationAuthenticationProvider
  48.  *
  49.  * Classe che utilizza le configurazioni utenti create tramite wildfly
  50.  *
  51.  * ...
  52.  * <b:bean id="wildflyApplicationAuthenticationProvider" class="org.openspcoop2.utils.jaxrs.impl.authentication.provider.WildflyApplicationAuthenticationProvider" >
  53.  *     <!-- <b:property name="userDetailsService" ref="userDetailServiceUtenze"/> -->
  54.  * </b:bean>
  55.  * ...
  56.  * <authentication-manager alias="authenticationManager">
  57.  *      <authentication-provider ref="wildflyApplicationAuthenticationProvider"/>
  58.  * </authentication-manager>
  59.  * ...
  60.  *
  61.  * @author Andrea Poli (poli@link.it)
  62.  * @author $Author$
  63.  * @version $Rev$, $Date$
  64.  */
  65. /**
  66.  * @author poli
  67.  *
  68.  */
  69. public class WildflyApplicationAuthenticationProvider implements AuthenticationProvider{

  70.     private Logger log = org.slf4j.LoggerFactory.getLogger(this.getClass());

  71.     private String configDir = "jboss.server.config.dir";
  72.     private String applicationUsersFileName = "application-users.properties";
  73.     private String applicationRolesFileName = "application-roles.properties";
  74.     private String realName = "ApplicationRealm";
  75.     private String hashAlgorithm = "MD5";
  76.     private String hashEncoding = "hex";
  77.     private UserDetailsService userDetailsService;
  78.    
  79.     private static String getS(String v) {
  80.         return "sec"+v+"ret";
  81.     }
  82.    
  83.     private static final String FILE_PREFIX = "File '";
  84.    
  85.     @Override
  86.     public Authentication authenticate(Authentication authentication) throws AuthenticationException {

  87.         String username = authentication.getName();
  88.         Object passwordObject = authentication.getCredentials();
  89.         String password = (String) passwordObject;

  90.         if(username==null || password==null) {
  91.             throw new AuthenticationCredentialsNotFoundException("Credentials not found");
  92.         }

  93.         String confDir = System.getProperty(this.configDir);
  94.         if(confDir==null) {
  95.             throw new ProviderNotFoundException("Property '"+this.configDir+"' not found");
  96.         }
  97.         File confDirJBoss = new File(confDir);
  98.         String prefixConfDirJboss = FILE_PREFIX+confDirJBoss.getAbsolutePath()+"' ";
  99.         if(!confDirJBoss.exists()) {
  100.             throw new ProviderNotFoundException(prefixConfDirJboss+"not exists");
  101.         }
  102.         if(!confDirJBoss.isDirectory()) {
  103.             throw new ProviderNotFoundException(prefixConfDirJboss+"isn't directory");
  104.         }

  105.         // check utenza da file application-users.properties
  106.         File fUsers = new File(confDirJBoss, this.applicationUsersFileName);
  107.         String prefixFUsers = FILE_PREFIX+fUsers.getAbsolutePath()+"' ";
  108.         if(!fUsers.exists()) {
  109.             throw new ProviderNotFoundException(prefixFUsers+"not exists");
  110.         }
  111.         if(!fUsers.canRead()) {
  112.             throw new ProviderNotFoundException(prefixFUsers+"cannot read");
  113.         }
  114.         Properties pUsers = new Properties();
  115.         try (FileInputStream fin = new FileInputStream(fUsers)){
  116.             pUsers.load(fin);
  117.         }catch(Exception e) {
  118.             String msg = prefixFUsers+"process error: "+e.getMessage();
  119.             this.log.error(msg,e.getMessage());
  120.             throw new ProviderNotFoundException(msg);
  121.         }
  122.         Iterator<?> itUsers = pUsers.keySet().iterator();
  123.         boolean found = false;
  124.         String passwordEncoded = null;
  125.         while (itUsers.hasNext()) {
  126.             String user = (String) itUsers.next();
  127.             passwordEncoded =  pUsers.getProperty(user);
  128.             if(username.equals(user)) {
  129.                 found = true;
  130.                 break;
  131.             }
  132.         }
  133.         if(!found) {
  134.             /**throw new UsernameNotFoundException("Username '"+username+"' not found");*/
  135.             // Fix security: Make sure allowing user enumeration is safe here.
  136.             throw new BadCredentialsException("Bad credentials");
  137.         }

  138.         // Check password
  139.         String clearTextPassword=username+":"+this.realName+":"+password;
  140.         String hashedPassword=null;
  141.         try {
  142.             hashedPassword=encode(clearTextPassword, this.hashAlgorithm, this.hashEncoding);
  143.         }catch(Exception e) {
  144.             String msg = "Password verifier failed: "+e.getMessage();
  145.             logAndThrowAuthenticationServiceException(msg,e);
  146.         }
  147.         if(!passwordEncoded.equals(hashedPassword)) {
  148.             throw new BadCredentialsException("Bad credentials");
  149.         }

  150.         // check ruoli utenza da file application-roles.properties
  151.         List<GrantedAuthority> roles = new ArrayList<>();
  152.         File fRoles = new File(confDirJBoss, this.applicationRolesFileName);
  153.         if(!fRoles.exists()) {
  154.             throw new ProviderNotFoundException(FILE_PREFIX+fRoles.getAbsolutePath()+"' not exists");
  155.         }
  156.         if(!fRoles.canRead()) {
  157.             throw new ProviderNotFoundException(FILE_PREFIX+fRoles.getAbsolutePath()+"' cannot read");
  158.         }
  159.         Properties pRoles = new Properties();
  160.         try (FileInputStream fin = new FileInputStream(fRoles)){
  161.             pRoles.load(fin);
  162.         }catch(Exception e) {
  163.             String msg = FILE_PREFIX+fRoles.getAbsolutePath()+"' process error: "+e.getMessage();
  164.             this.log.error(msg,e.getMessage());
  165.             throw new ProviderNotFoundException(msg);
  166.         }
  167.         Iterator<?> itRoles = pRoles.keySet().iterator();
  168.         while (itRoles.hasNext()) {
  169.             String user = (String) itRoles.next();
  170.             if(username.equals(user)) {
  171.                 String userRoles =  pRoles.getProperty(user);
  172.                 if(userRoles!=null && !"".equals(userRoles)) {
  173.                     String [] tmp = userRoles.split(",");
  174.                     for (int i = 0; i < tmp.length; i++) {
  175.                         GrantedAuthority grant = new SimpleGrantedAuthority(tmp[i].trim());
  176.                         roles.add(grant);
  177.                     }
  178.                 }
  179.                 break;
  180.             }
  181.         }

  182.         // Wrap in UsernamePasswordAuthenticationToken
  183.         UsernamePasswordAuthenticationToken userAuth = null;
  184.         if(this.userDetailsService!=null) {
  185.             try {
  186.                 UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
  187.                 userAuth = new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
  188.             }catch(UsernameNotFoundException e){
  189.                 String msg = "User '"+username+"' unknown: "+e.getMessage();
  190.                 logAndThrowBadCredentialsException(msg,e);
  191.             }
  192.         }
  193.         else {  
  194.             User user = new User(username, getS(""), true, true, true, true, roles);
  195.             userAuth = new UsernamePasswordAuthenticationToken(user, getS(""), user.getAuthorities());
  196.         }
  197.         userAuth.setDetails(authentication.getDetails());
  198.         return userAuth;
  199.        
  200.        

  201.     }
  202.    
  203.     private void logAndThrowAuthenticationServiceException(String msg, Exception e) throws AuthenticationServiceException {
  204.         this.log.error(msg,e.getMessage());
  205.         throw new AuthenticationServiceException(msg,e);
  206.     }
  207.     private void logAndThrowBadCredentialsException(String msg, Exception e) throws BadCredentialsException {
  208.         this.log.debug(msg,e);
  209.         throw new BadCredentialsException(msg,e);
  210.     }
  211.    

  212.     @Override
  213.     public boolean supports(Class<?> authentication) {
  214.         return authentication.equals(UsernamePasswordAuthenticationToken.class);
  215.     }

  216.    
  217.     public static final String BASE64_ENCODING = "BASE64";
  218.     public static final String HEX_ENCODING = "HEX";
  219.     private String encode(String password, String hashAlgorithm, String hashEncoding) throws UtilsException {
  220.         String passwordHash = null;

  221.         byte[] passBytes = password.getBytes();
  222.        
  223.         // calculate the hash and apply the encoding.
  224.         byte[] hash = null;
  225.         try{
  226.             MessageDigest md = MessageDigest.getInstance(hashAlgorithm);
  227.             md.update(passBytes);
  228.             hash = md.digest();
  229.         }catch(Exception e)
  230.         {
  231.             throw new UtilsException("MessageDigest processing ('"+hashAlgorithm+"') failed: "+e.getMessage(),e);
  232.         }
  233.         if(hashEncoding.equalsIgnoreCase(BASE64_ENCODING))
  234.         {
  235.             passwordHash = Base64Utilities.encodeAsString(hash);
  236.         }
  237.         else if(hashEncoding.equalsIgnoreCase(HEX_ENCODING))
  238.         {
  239.             passwordHash = HexBinaryUtilities.encodeAsString(hash);
  240.         }
  241.         else
  242.         {
  243.             throw new UtilsException("Unsupported hashAlgorithm '"+hashAlgorithm+"'");
  244.         }

  245.         return passwordHash;
  246.     }
  247.    
  248.     public String getConfigDir() {
  249.         return this.configDir;
  250.     }
  251.     public void setConfigDir(String configDir) {
  252.         this.configDir = configDir;
  253.     }

  254.     public String getApplicationUsersFileName() {
  255.         return this.applicationUsersFileName;
  256.     }
  257.     public void setApplicationUsersFileName(String applicationUsersFileName) {
  258.         this.applicationUsersFileName = applicationUsersFileName;
  259.     }

  260.     public String getApplicationRolesFileName() {
  261.         return this.applicationRolesFileName;
  262.     }
  263.     public void setApplicationRolesFileName(String applicationRolesFileName) {
  264.         this.applicationRolesFileName = applicationRolesFileName;
  265.     }

  266.     public String getRealName() {
  267.         return this.realName;
  268.     }
  269.     public void setRealName(String realName) {
  270.         this.realName = realName;
  271.     }

  272.     public String getHashAlgorithm() {
  273.         return this.hashAlgorithm;
  274.     }
  275.     public void setHashAlgorithm(String hashAlgorithm) {
  276.         this.hashAlgorithm = hashAlgorithm;
  277.     }

  278.     public String getHashEncoding() {
  279.         return this.hashEncoding;
  280.     }
  281.     public void setHashEncoding(String hashEncoding) {
  282.         this.hashEncoding = hashEncoding;
  283.     }
  284.    
  285.     public UserDetailsService getUserDetailsService() {
  286.         return this.userDetailsService;
  287.     }
  288.     public void setUserDetailsService(UserDetailsService userDetailsService) {
  289.         this.userDetailsService = userDetailsService;
  290.     }


  291. }