extensions/net.sf.basedb.yubikey/trunk/src/net/sf/basedb/yubikey/YubiKey.java

Code
Comments
Other
Rev Date Author Line
2249 25 Feb 14 nicklas 1 /**
2249 25 Feb 14 nicklas 2   $Id $
2249 25 Feb 14 nicklas 3
2249 25 Feb 14 nicklas 4   Copyright (C) 2014 Nicklas Nordborg
2249 25 Feb 14 nicklas 5
2249 25 Feb 14 nicklas 6   This file is part of BASE - BioArray Software Environment.
2249 25 Feb 14 nicklas 7   Available at http://base.thep.lu.se/
2249 25 Feb 14 nicklas 8
2249 25 Feb 14 nicklas 9   BASE is free software; you can redistribute it and/or
2249 25 Feb 14 nicklas 10   modify it under the terms of the GNU General Public License
2249 25 Feb 14 nicklas 11   as published by the Free Software Foundation; either version 3
2249 25 Feb 14 nicklas 12   of the License, or (at your option) any later version.
2249 25 Feb 14 nicklas 13
2249 25 Feb 14 nicklas 14   BASE is distributed in the hope that it will be useful,
2249 25 Feb 14 nicklas 15   but WITHOUT ANY WARRANTY; without even the implied warranty of
2249 25 Feb 14 nicklas 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2249 25 Feb 14 nicklas 17   GNU General Public License for more details.
2249 25 Feb 14 nicklas 18
2249 25 Feb 14 nicklas 19   You should have received a copy of the GNU General Public License
2249 25 Feb 14 nicklas 20   along with BASE. If not, see <http://www.gnu.org/licenses/>.
2249 25 Feb 14 nicklas 21 */
2252 25 Feb 14 nicklas 22 package net.sf.basedb.yubikey;
2249 25 Feb 14 nicklas 23
5182 06 Dec 18 nicklas 24 import java.io.File;
2257 27 Feb 14 nicklas 25 import java.io.InputStream;
2257 27 Feb 14 nicklas 26 import java.net.URL;
2511 17 Jun 14 nicklas 27 import java.util.Arrays;
2511 17 Jun 14 nicklas 28 import java.util.HashSet;
2257 27 Feb 14 nicklas 29 import java.util.Properties;
2511 17 Jun 14 nicklas 30 import java.util.Set;
2257 27 Feb 14 nicklas 31
2258 28 Feb 14 nicklas 32 import com.yubico.client.v2.YubicoClient;
2258 28 Feb 14 nicklas 33
2257 27 Feb 14 nicklas 34 import net.sf.basedb.core.ConfigurationException;
2255 26 Feb 14 nicklas 35 import net.sf.basedb.core.authentication.AuthenticationMethod;
5182 06 Dec 18 nicklas 36 import net.sf.basedb.util.FileUtil;
2257 27 Feb 14 nicklas 37 import net.sf.basedb.util.Values;
2255 26 Feb 14 nicklas 38
2249 25 Feb 14 nicklas 39 /**
2249 25 Feb 14 nicklas 40   Global constants for the YubiKey package.
2249 25 Feb 14 nicklas 41   @author Nicklas
2249 25 Feb 14 nicklas 42   @since 1.0
2249 25 Feb 14 nicklas 43 */
2257 27 Feb 14 nicklas 44 public final class YubiKey 
2249 25 Feb 14 nicklas 45 {
2249 25 Feb 14 nicklas 46   /**
2249 25 Feb 14 nicklas 47     The current version of this package.
2249 25 Feb 14 nicklas 48   */
5569 15 Aug 19 nicklas 49   public static final String VERSION = "1.7-dev";
2249 25 Feb 14 nicklas 50
2249 25 Feb 14 nicklas 51
2255 26 Feb 14 nicklas 52   public static final AuthenticationMethod AUTHENTICATION_METHOD = AuthenticationMethod.getInstance("yubikey");
2255 26 Feb 14 nicklas 53   
5182 06 Dec 18 nicklas 54   private static File configFile;
5182 06 Dec 18 nicklas 55   private static long configFileLastModifed;
2257 27 Feb 14 nicklas 56   private static Properties config;
2257 27 Feb 14 nicklas 57   private static Integer clientId;
2257 27 Feb 14 nicklas 58   private static String clientKey;
2511 17 Jun 14 nicklas 59   private static Set<String> noYubiKeyLogin;
2257 27 Feb 14 nicklas 60   
3993 10 Jun 16 nicklas 61   /** 
3993 10 Jun 16 nicklas 62     @since 1.3 
3993 10 Jun 16 nicklas 63   */
3993 10 Jun 16 nicklas 64   private static Set<String> requireYubiKeyLogin;
3993 10 Jun 16 nicklas 65   
2257 27 Feb 14 nicklas 66   /**
5156 30 Nov 18 nicklas 67     @since 1.5
5156 30 Nov 18 nicklas 68   */
5156 30 Nov 18 nicklas 69   private static Set<String> allowedAuthenticationMethods;
5156 30 Nov 18 nicklas 70   
5156 30 Nov 18 nicklas 71   /**
2257 27 Feb 14 nicklas 72     Load configuration file: /yubikey.properties
5184 06 Dec 18 nicklas 73     If checkModified=true changes to the configuration file are detected
5184 06 Dec 18 nicklas 74     and reloaded if needed.
2257 27 Feb 14 nicklas 75   */
5184 06 Dec 18 nicklas 76   public static synchronized final Properties getConfig(boolean checkModified)
2257 27 Feb 14 nicklas 77   {
5184 06 Dec 18 nicklas 78     if (checkModified && configFile != null && configFile.lastModified() != configFileLastModifed)
5182 06 Dec 18 nicklas 79     {
5182 06 Dec 18 nicklas 80       // The configuration has changed, reset configuration and force reload
5182 06 Dec 18 nicklas 81       config = null;
5182 06 Dec 18 nicklas 82       configFile = null;
5182 06 Dec 18 nicklas 83     }
2257 27 Feb 14 nicklas 84     if (config == null)
2257 27 Feb 14 nicklas 85     {
5182 06 Dec 18 nicklas 86       InputStream is = null;
2257 27 Feb 14 nicklas 87       try
2257 27 Feb 14 nicklas 88       {
2257 27 Feb 14 nicklas 89         URL configUrl = YubiKey.class.getResource("/yubikey.properties");
5182 06 Dec 18 nicklas 90         is = configUrl == null ? null : configUrl.openStream();
2257 27 Feb 14 nicklas 91         if (is == null)
2257 27 Feb 14 nicklas 92         {
2257 27 Feb 14 nicklas 93           throw new ConfigurationException("Can't find the configuration file. " +
2257 27 Feb 14 nicklas 94               "Make sure '/yubikey.properties' is in the CLASSPATH.");
2257 27 Feb 14 nicklas 95         }
5182 06 Dec 18 nicklas 96         if (configUrl.getProtocol().equals("file"))
5182 06 Dec 18 nicklas 97         {
5182 06 Dec 18 nicklas 98           File f = new File(configUrl.getPath());
5182 06 Dec 18 nicklas 99           if (f.exists())
5182 06 Dec 18 nicklas 100           {
5182 06 Dec 18 nicklas 101             configFile = f;
5182 06 Dec 18 nicklas 102             configFileLastModifed = configFile.lastModified();
5182 06 Dec 18 nicklas 103           }
5182 06 Dec 18 nicklas 104         }
2257 27 Feb 14 nicklas 105         config = new Properties();
2257 27 Feb 14 nicklas 106         config.load(is);
2257 27 Feb 14 nicklas 107       }
2257 27 Feb 14 nicklas 108       catch (Exception ex)
2257 27 Feb 14 nicklas 109       {
2257 27 Feb 14 nicklas 110         throw new ConfigurationException(ex.getMessage(), ex);
2257 27 Feb 14 nicklas 111       }
5182 06 Dec 18 nicklas 112       finally
5182 06 Dec 18 nicklas 113       {
5182 06 Dec 18 nicklas 114         FileUtil.close(is);
5182 06 Dec 18 nicklas 115       }
2257 27 Feb 14 nicklas 116       
2257 27 Feb 14 nicklas 117       clientId = Values.getInteger(config.getProperty("client-id"), null);
2257 27 Feb 14 nicklas 118       clientKey = config.getProperty("client-key");
2257 27 Feb 14 nicklas 119       
2257 27 Feb 14 nicklas 120       if (clientId == null || clientKey == null) 
2257 27 Feb 14 nicklas 121       {
2257 27 Feb 14 nicklas 122         // Invalid configuration
2257 27 Feb 14 nicklas 123         config = null;
2257 27 Feb 14 nicklas 124         clientId = null;
2257 27 Feb 14 nicklas 125         clientKey = null;
2257 27 Feb 14 nicklas 126         throw new ConfigurationException("Missing configuration value: client-id or client-key");
2257 27 Feb 14 nicklas 127       }
2511 17 Jun 14 nicklas 128       
2511 17 Jun 14 nicklas 129       String noYubiKey  = config.getProperty("no-yubikey");
2511 17 Jun 14 nicklas 130       if (noYubiKey != null)
2511 17 Jun 14 nicklas 131       {
2511 17 Jun 14 nicklas 132         noYubiKeyLogin = new HashSet<String>(Arrays.asList(noYubiKey.split("[\\s,]+")));
2511 17 Jun 14 nicklas 133       }
3993 10 Jun 16 nicklas 134       
3993 10 Jun 16 nicklas 135       String requireYubiKey  = config.getProperty("require-yubikey");
3993 10 Jun 16 nicklas 136       if (requireYubiKey != null)
3993 10 Jun 16 nicklas 137       {
3993 10 Jun 16 nicklas 138         requireYubiKeyLogin = new HashSet<String>(Arrays.asList(requireYubiKey.split("[\\s,]+")));
3993 10 Jun 16 nicklas 139       }
5156 30 Nov 18 nicklas 140       
5156 30 Nov 18 nicklas 141       String otherMethods = config.getProperty("allow-other-authentication");
5156 30 Nov 18 nicklas 142       if (otherMethods != null)
5156 30 Nov 18 nicklas 143       {
5156 30 Nov 18 nicklas 144         allowedAuthenticationMethods = new HashSet<String>(Arrays.asList(otherMethods.split("[\\s,]+")));
5156 30 Nov 18 nicklas 145       }
2257 27 Feb 14 nicklas 146     }
2257 27 Feb 14 nicklas 147     return config;
2257 27 Feb 14 nicklas 148   }
2257 27 Feb 14 nicklas 149   
2257 27 Feb 14 nicklas 150   /**
2257 27 Feb 14 nicklas 151     Get the configured CLIENT_ID to use when validating passwords
2257 27 Feb 14 nicklas 152     with the YubiCloud service.
2257 27 Feb 14 nicklas 153   */
2257 27 Feb 14 nicklas 154   public static Integer getClientId()
2257 27 Feb 14 nicklas 155   {
2257 27 Feb 14 nicklas 156     return clientId;
2257 27 Feb 14 nicklas 157   }
2257 27 Feb 14 nicklas 158   
2257 27 Feb 14 nicklas 159   /**
2257 27 Feb 14 nicklas 160     Get the configured CLIENT_KEY to use when validating passwords
2257 27 Feb 14 nicklas 161     with the YubiCloud service.
2257 27 Feb 14 nicklas 162   */
2257 27 Feb 14 nicklas 163   public static String getClientKey()
2257 27 Feb 14 nicklas 164   {
2257 27 Feb 14 nicklas 165     return clientKey;
2257 27 Feb 14 nicklas 166   }
2258 28 Feb 14 nicklas 167   
2258 28 Feb 14 nicklas 168   /**
2511 17 Jun 14 nicklas 169     Check if YubiKey login has been disabled for the given client id. 
2511 17 Jun 14 nicklas 170     To disable a client, the id should be listed in no-yubikey setting
2511 17 Jun 14 nicklas 171     in yubikey.properties configuration file.
2511 17 Jun 14 nicklas 172     
3993 10 Jun 16 nicklas 173     @param clientId The external id of the client application
2511 17 Jun 14 nicklas 174     @return TRUE if YubiKey is disabled, FALSE if no
2511 17 Jun 14 nicklas 175   */
2511 17 Jun 14 nicklas 176   public static boolean isYubiKeyDisabledForClient(String clientId)
2511 17 Jun 14 nicklas 177   {
2511 17 Jun 14 nicklas 178     return clientId != null && noYubiKeyLogin != null && noYubiKeyLogin.contains(clientId);
2511 17 Jun 14 nicklas 179   }
2511 17 Jun 14 nicklas 180   
2511 17 Jun 14 nicklas 181   /**
3993 10 Jun 16 nicklas 182     Check if YubiKey login is required for the given client id. 
3993 10 Jun 16 nicklas 183     To require a client to use YubiKey, the id should be listed in 
3993 10 Jun 16 nicklas 184     the require-yubikey setting in yubikey.properties configuration file.
3993 10 Jun 16 nicklas 185     
3993 10 Jun 16 nicklas 186     @param clientId The external id of the client application
3993 10 Jun 16 nicklas 187     @return TRUE if YubiKey is required, FALSE if not
3993 10 Jun 16 nicklas 188     @since 1.3
3993 10 Jun 16 nicklas 189   */
3993 10 Jun 16 nicklas 190   public static boolean isYubiKeyRequiredForClient(String clientId)
3993 10 Jun 16 nicklas 191   {
3993 10 Jun 16 nicklas 192     return clientId != null && requireYubiKeyLogin != null && requireYubiKeyLogin.contains(clientId);
3993 10 Jun 16 nicklas 193   }
3993 10 Jun 16 nicklas 194   
3993 10 Jun 16 nicklas 195   /**
5156 30 Nov 18 nicklas 196     Check if the authentication method is allowed. By default the 'yubikey' 
5156 30 Nov 18 nicklas 197     is the only one allowed, but also methods listed in the 'allow-other-authentication'
5156 30 Nov 18 nicklas 198     setting in the 'yubikey.properties' file.
5156 30 Nov 18 nicklas 199
5156 30 Nov 18 nicklas 200     @param auth The authentication method to check
5156 30 Nov 18 nicklas 201     @return TRUE if the authentication method is allowed, FALSE if not
5156 30 Nov 18 nicklas 202     @since 1.5
5156 30 Nov 18 nicklas 203   */
5156 30 Nov 18 nicklas 204   public static boolean isAuthenticationMethodAllowed(AuthenticationMethod auth)
5156 30 Nov 18 nicklas 205   {
5156 30 Nov 18 nicklas 206     if (auth == null) return false;
5156 30 Nov 18 nicklas 207     if (auth == AUTHENTICATION_METHOD) return true;
5156 30 Nov 18 nicklas 208     if (allowedAuthenticationMethods == null) return false;
5156 30 Nov 18 nicklas 209     return allowedAuthenticationMethods.contains("*") || allowedAuthenticationMethods.contains(auth.getMethod());
5156 30 Nov 18 nicklas 210   }
5156 30 Nov 18 nicklas 211   
5156 30 Nov 18 nicklas 212   /**
2258 28 Feb 14 nicklas 213     Get a YubicoClient configured for verification of passwords.
2258 28 Feb 14 nicklas 214   */
2258 28 Feb 14 nicklas 215   public static YubicoClient getYubicoClient()
2258 28 Feb 14 nicklas 216   {
3991 10 Jun 16 nicklas 217     YubicoClient client = YubicoClient.getClient(getClientId(), getClientKey());
2258 28 Feb 14 nicklas 218     return client;
2258 28 Feb 14 nicklas 219   }
2249 25 Feb 14 nicklas 220 }