ApiKeyUtilities.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.pdd.core.autenticazione;

  21. import java.util.List;

  22. import org.openspcoop2.core.config.ServizioApplicativo;
  23. import org.openspcoop2.core.config.driver.db.DriverConfigurazioneDB;
  24. import org.openspcoop2.core.id.IDServizioApplicativo;
  25. import org.openspcoop2.core.id.IDSoggetto;
  26. import org.openspcoop2.core.registry.Soggetto;
  27. import org.openspcoop2.core.registry.driver.db.DriverRegistroServiziDB;
  28. import org.openspcoop2.pdd.core.PdDContext;
  29. import org.openspcoop2.pdd.core.connettori.InfoConnettoreIngresso;
  30. import org.openspcoop2.utils.crypt.PasswordGenerator;
  31. import org.openspcoop2.utils.io.Base64Utilities;

  32. /**
  33.  * ApiKeyUtilities
  34.  *
  35.  * @author Andrea Poli (apoli@link.it)
  36.  * @author $Author$
  37.  * @version $Rev$, $Date$
  38.  */
  39. public class ApiKeyUtilities {

  40.     public static String getKey(boolean apiKey,
  41.             boolean header, boolean cookie, boolean queryParameter,
  42.             String nomeHeader, String nomeCookie, String nomeQueryParameter,
  43.             InfoConnettoreIngresso infoConnettore, PdDContext pddContext, boolean throwException,
  44.             StringBuilder fullCredential) throws AutenticazioneException {
  45.        
  46.         String tipo = apiKey ? "ApiKey" : "AppId";
  47.        
  48.         String key = null;
  49.        
  50.         // viene usato l'ordine della specifica
  51.        
  52.         if(queryParameter) {
  53.             if(nomeQueryParameter==null && throwException) {
  54.                 throw new AutenticazioneException("Nome del parametro della query, da cui estrarre l'"+tipo+", non indicato");
  55.             }
  56.             if(nomeQueryParameter!=null && infoConnettore!=null && infoConnettore.getUrlProtocolContext()!=null) {
  57.                 key = infoConnettore.getUrlProtocolContext().getParameterFirstValue(nomeQueryParameter);
  58.                 if(key!=null && "".equals(key.trim())) {
  59.                     key = null;
  60.                 }
  61.             }
  62.         }
  63.         if(key!=null) {
  64.             if(fullCredential.length()>0) {
  65.                 fullCredential.append("\n");
  66.             }
  67.             fullCredential.append(tipo).append(" (query) '").append(nomeQueryParameter);
  68.             if(!apiKey) { // l'api key non deve essere tracciata come per la password.
  69.                 fullCredential.append(": ").append(key);
  70.             }
  71.             fullCredential.append("'");
  72.             return key;
  73.         }
  74.        
  75.         if(header) {
  76.             if(nomeHeader==null && throwException) {
  77.                 throw new AutenticazioneException("Nome dell'header, da cui estrarre l'"+tipo+", non indicato");
  78.             }
  79.             if(nomeHeader!=null && infoConnettore!=null && infoConnettore.getUrlProtocolContext()!=null) {
  80.                 key = infoConnettore.getUrlProtocolContext().getHeaderFirstValue(nomeHeader);
  81.                 if(key!=null && "".equals(key.trim())) {
  82.                     key = null;
  83.                 }
  84.             }
  85.         }
  86.         if(key!=null) {
  87.             if(fullCredential.length()>0) {
  88.                 fullCredential.append("\n");
  89.             }
  90.             fullCredential.append(tipo).append(" (http) '").append(nomeHeader);
  91.             if(!apiKey) { // l'api key non deve essere tracciata come per la password.
  92.                 fullCredential.append(": ").append(key);
  93.             }
  94.             fullCredential.append("'");
  95.             return key;
  96.         }
  97.        
  98.         if(cookie) {
  99.             if(nomeCookie==null && throwException) {
  100.                 throw new AutenticazioneException("Nome del cookie, da cui estrarre l'"+tipo+", non indicato");
  101.             }
  102.             if(nomeCookie!=null && infoConnettore!=null && infoConnettore.getUrlProtocolContext()!=null) {
  103.                 key = infoConnettore.getUrlProtocolContext().getCookieValue(nomeCookie);
  104.                 if(key!=null && "".equals(key.trim())) {
  105.                     key = null;
  106.                 }
  107.             }
  108.         }
  109.         if(key!=null) {
  110.             if(fullCredential.length()>0) {
  111.                 fullCredential.append("\n");
  112.             }
  113.             fullCredential.append(tipo).append(" (cookie) '").append(nomeCookie);
  114.             if(!apiKey) { // l'api key non deve essere tracciata come per la password.
  115.                 fullCredential.append(": ").append(key);
  116.             }
  117.             fullCredential.append("'");
  118.             return key;
  119.         }
  120.        
  121.         if(throwException) {
  122.             throw new AutenticazioneException(tipo+" non presente nella richiesta");
  123.         }
  124.            
  125.         return null;
  126.     }
  127.    
  128.     private static final String SOGGETTO_SEPARATOR = ".";  
  129.     public static final String APPLICATIVO_SOGGETTO_SEPARATOR = "@";
  130.     private static final int MAX_ALREADY_EXISTS = 5000;
  131.     private static final String SEPARATOR_ALREADY_EXISTS = ".";
  132.    
  133.     public static String toAppId(String protocollo, IDSoggetto idSoggetto, boolean multipleApiKeys, DriverRegistroServiziDB driver) throws Exception {
  134.         String appId = _toAppId(protocollo, idSoggetto);
  135.         if(!_existsAppId(appId, multipleApiKeys, idSoggetto, driver)) {
  136.             return appId;
  137.         }
  138.         for (int i = 2; i < MAX_ALREADY_EXISTS; i++) {
  139.             IDSoggetto idSoggettoAlreadyExists = new IDSoggetto(idSoggetto.getTipo(), idSoggetto.getNome()+SEPARATOR_ALREADY_EXISTS+i);
  140.             String appIdAlreadyExists = _toAppId(protocollo, idSoggettoAlreadyExists);
  141.             if(!_existsAppId(appIdAlreadyExists, multipleApiKeys, idSoggetto, driver)) {
  142.                 return appIdAlreadyExists;
  143.             }
  144.         }
  145.         throw new Exception("Generazione appId univoco non riuscita dopo "+MAX_ALREADY_EXISTS+" tentativi");
  146.     }
  147.     private static String _toAppId(String protocollo, IDSoggetto idSoggetto) throws Exception {
  148.         // non va bene perchè due nomi uguali di due protocolli differenti, vengono identici.
  149.         //return org.openspcoop2.protocol.engine.utils.NamingUtils.getLabelSoggetto(protocollo, idSoggetto.getTipo(), idSoggetto.getNome());    
  150.         if(idSoggetto==null || idSoggetto.getTipo()==null || idSoggetto.getNome()==null) {
  151.             throw new Exception("Identificativo soggetto non definito");
  152.         }
  153.         return idSoggetto.getNome()+SOGGETTO_SEPARATOR+idSoggetto.getTipo();
  154.     }
  155.     private static boolean _existsAppId(String appId, boolean multipleApiKeys, IDSoggetto idSoggetto, DriverRegistroServiziDB driver) throws Exception {
  156.         Soggetto soggetto = driver.soggettoWithCredenzialiApiKey(appId, multipleApiKeys);
  157.         if(soggetto==null) {
  158.             return false;
  159.         }
  160.         boolean isSame = false;
  161.         if(soggetto.getTipo().equals(idSoggetto.getTipo()) &&
  162.                 soggetto.getNome().equals(idSoggetto.getNome()) ) {
  163.             isSame = true;
  164.         }
  165.         return !isSame;
  166.     }
  167.    
  168.     public static String toAppId(String protocollo, IDServizioApplicativo idSA, boolean multipleApiKeys, DriverConfigurazioneDB driver) throws Exception {
  169.         String appId = _toAppId(protocollo, idSA.getNome(), idSA.getIdSoggettoProprietario());
  170.         if(!_existsAppId(appId, multipleApiKeys, idSA, driver)) {
  171.             return appId;
  172.         }
  173.         for (int i = 2; i < MAX_ALREADY_EXISTS; i++) {
  174.             String appIdAlreadyExists = _toAppId(protocollo, idSA.getNome()+SEPARATOR_ALREADY_EXISTS+i, idSA.getIdSoggettoProprietario());
  175.             if(!_existsAppId(appIdAlreadyExists, multipleApiKeys, idSA, driver)) {
  176.                 return appIdAlreadyExists;
  177.             }
  178.         }
  179.         throw new Exception("Generazione appId univoco non riuscita dopo "+MAX_ALREADY_EXISTS+" tentativi");
  180.     }
  181.     private static String _toAppId(String protocollo, String nomeSA, IDSoggetto idSoggetto) throws Exception {
  182.         return nomeSA+APPLICATIVO_SOGGETTO_SEPARATOR+ _toAppId(protocollo, idSoggetto);
  183.     }
  184.     private static boolean _existsAppId(String appId, boolean multipleApiKeys,  IDServizioApplicativo idSA, DriverConfigurazioneDB driver) throws Exception {
  185.         List<ServizioApplicativo> saList = driver.servizioApplicativoWithCredenzialiApiKeyList(appId, multipleApiKeys);
  186.         if (saList==null || saList.isEmpty()) {
  187.             return false;
  188.         }
  189.         boolean isSame = false;
  190.         for (ServizioApplicativo servizioApplicativo : saList) {
  191.             if(!servizioApplicativo.getNome().equals(idSA.getNome())) {
  192.                 continue;
  193.             }
  194.             if(!servizioApplicativo.getTipoSoggettoProprietario().equals(idSA.getIdSoggettoProprietario().getTipo())) {
  195.                 continue;
  196.             }
  197.             if(!servizioApplicativo.getNomeSoggettoProprietario().equals(idSA.getIdSoggettoProprietario().getNome())) {
  198.                 continue;
  199.             }
  200.             isSame = true;
  201.             break;
  202.         }
  203.         return !isSame;
  204.     }
  205.            
  206.     private static final String PREFIX_SEPARATOR_API_KEY = ".";
  207.     private static final String PREFIX_SEPARATOR_API_KEY_REGEXP = "\\.";
  208.    
  209.     private static String getPrefixForApiKey(String protocollo, IDSoggetto idSoggetto, DriverRegistroServiziDB driver) throws Exception {
  210.         boolean multipleApiKeys = false;
  211.         String appId = toAppId(protocollo, idSoggetto, multipleApiKeys, driver);
  212.         return Base64Utilities.encodeAsString(appId.getBytes())+PREFIX_SEPARATOR_API_KEY;
  213.     }
  214.     public static ApiKey newApiKey(String protocollo, IDSoggetto idSoggetto, int length, DriverRegistroServiziDB driver) throws Exception {
  215.         ApiKey apiKey = new ApiKey();
  216.         String password = getPassword(length);
  217.         String apiKeyToken = getPrefixForApiKey(protocollo, idSoggetto, driver)+Base64Utilities.encodeAsString(password.getBytes());
  218.         apiKey.setApiKey(apiKeyToken);
  219.         apiKey.setPassword(password);
  220.         return apiKey;
  221.     }
  222.    
  223.     private static String getPrefixForApiKey(String protocollo, IDServizioApplicativo idSA, DriverConfigurazioneDB driver) throws Exception {
  224.         boolean multipleApiKeys = false;
  225.         String appId = toAppId(protocollo, idSA, multipleApiKeys, driver);
  226.         return Base64Utilities.encodeAsString(appId.getBytes())+PREFIX_SEPARATOR_API_KEY;
  227.     }
  228.     public static ApiKey newApiKey(String protocollo, IDServizioApplicativo idSA, int length, DriverConfigurazioneDB driver) throws Exception {
  229.         ApiKey apiKey = new ApiKey();
  230.         String password = getPassword(length);
  231.         String apiKeyToken = getPrefixForApiKey(protocollo, idSA, driver)+Base64Utilities.encodeAsString(password.getBytes());
  232.         apiKey.setApiKey(apiKeyToken);
  233.         apiKey.setPassword(password);
  234.         return apiKey;
  235.     }
  236.    
  237.     public static String encodeApiKey(String appId, String password) throws Exception {
  238.         return Base64Utilities.encodeAsString(appId.getBytes())+
  239.             PREFIX_SEPARATOR_API_KEY+
  240.             Base64Utilities.encodeAsString(password.getBytes());
  241.     }
  242.    
  243.     public static String[] decodeApiKey(String apiKeyBase64) throws Exception {
  244.         if(!apiKeyBase64.contains(PREFIX_SEPARATOR_API_KEY)) {
  245.             throw new Exception("Formato non corretto");
  246.         }
  247.         String [] tmp = apiKeyBase64.split(PREFIX_SEPARATOR_API_KEY_REGEXP);
  248.         if(tmp==null || tmp.length!=2){
  249.             throw new Exception("Formato non corretto (.)");
  250.         }
  251.         try {
  252.             tmp[0] = new String(Base64Utilities.decode(tmp[0]));
  253.         }catch(Exception e) {
  254.             throw new Exception("Formato non corretto (appId)",e);
  255.         }
  256.         try {
  257.             tmp[1] = new String(Base64Utilities.decode(tmp[1]));
  258.         }catch(Exception e) {
  259.             throw new Exception("Formato non corretto (appKey)",e);
  260.         }
  261.         return tmp;
  262.     }
  263.    
  264.    
  265.     public static ApiKey newMultipleApiKey(int length) throws Exception {
  266.         ApiKey apiKey = new ApiKey();
  267.         String password = getPassword(length);
  268.         String apiKeyToken = encodeMultipleApiKey(password);
  269.         apiKey.setApiKey(apiKeyToken);
  270.         apiKey.setPassword(password);
  271.         return apiKey;
  272.     }
  273.    
  274.     public static String decodeMultipleApiKey(String apiKeyBase64) throws Exception {
  275.         return new String(Base64Utilities.decode(apiKeyBase64));
  276.     }
  277.     public static String encodeMultipleApiKey(String password) throws Exception {
  278.         return Base64Utilities.encodeAsString(password.getBytes());
  279.     }
  280.    
  281.     private static String getPassword(int length) throws Exception {
  282.         PasswordGenerator pwdGenerator = PasswordGenerator.DEFAULT;
  283.         return pwdGenerator.generate(length);
  284.     }
  285. }