All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.authlete.common.conf.AuthletePropertiesConfiguration Maven / Gradle / Ivy

Go to download

Authlete Java library used commonly by service implementations and the Authlete server.

There is a newer version: 4.15
Show newest version
/*
 * Copyright (C) 2014-2022 Authlete, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.authlete.common.conf;


import java.util.logging.Logger;
import com.authlete.common.util.PropertiesLoader;
import com.authlete.common.util.TypedProperties;
import com.neovisionaries.security.AESCipher;


/**
 * Implementation of {@link AuthleteConfiguration} based on
 * a properties file.
 *
 * 

* This is a utility class to load a configuration file that includes * properties related to Authlete. Below is the list of configuration * properties. *

* *
*
*
{@code base_url}
*
* The base URL of Authlete Web API. The default value is * {@code "https://api.authlete.com"}. *

*
* *
{@code service_owner.api_key}
*
* The service owner API key issued by Authlete. *

*
* *
{@code service_owner.api_secret.encrypted}
*
* The service owner API secret issued by Authlete, encrypted by * {@code "AES/CBC/PKCS5Padding"} and encoded in Base64. * The secret key and the initial vector of the encryption * have to be passed to the constructor of this class. *

*
* *
{@code service_owner.api_secret}
*
* The service owner API secret issued by Authlete. The value * of this configuration property is referred to only when * {@code service_owner.api_secret.encrypted} is not found in * the configuration file. *

*
* *
{@code service.api_key}
*
* The service API key issued by Authlete. *

*
* *
{@code service.api_secret.encrypted}
*
* The service API secret issued by Authlete, encrypted by * {@code "AES/CBC/PKCS5Padding"} and encoded in Base64. * The secret key and the initial vector of the encryption * have to be passed to the constructor of this class. *

*
* *
{@code service.api_secret}
*
* The service API secret issued by Authlete. The value of * of this configuration property is referred to only when * {@code service.api_secret.encrypted} is not found in the * configuration file. *
*
*
* *

* The value of {@code service_owner.api_secret.encrypted} can be * generated using {@code openssl} command like the following. *

* *
 * echo -n "{Service-Owner-API-Secret}" | openssl aes-128-cbc -e -a \
 *   -K  "{Your-Secret-Key-in-Hex}" -iv "{Your-Initial-Vector-in-Hex}"
* *

* "{Service-Owner-API-Secret}" is the service owner API secret * issued by Authlete. Values of "{Your-Secret-Key-in-Hex}" and * "{Your-Initial-Vector-in-Hex}" are 32-letter hex strings which * you can determine. The following is an example to generate a random * 32-letter hex string. *

* *
 * ruby -e 'puts Random.new.bytes(16).unpack("H*")'
* *

* Likewise, the value of {@code service.api_secret.encrypted} can be * generated by {@code openssl}, too. *

* *

* If you encrypt your service owner API secret and service API secret * as shown below: *

* *
 * // Encrypt service owner API secret.
 * $ echo -n "AF4Sms0cqs3HsTNlVrPbnWz5AXi3GtmMcveOklYKVCc" | openssl aes-128-cbc -e -a \
 *   -K a281ac2de1195e8c91ea383d38d05d1c -iv b6f5d0f0dd7146b0e3915ebd2dd078f3
 * sKzcMU98a8xA5lwR23Crfkyu23klZnTuQlWApyllARpHFv84IItoZFZXj70OCrnF
 *
 * // Encrypt service API secret.
 * $ echo -n "9La-ZhyyKK6sV6zsteNmcoTizHmC0NEVTFT9FUrIaYs" | openssl aes-128-cbc -e -a \
 *   -K a281ac2de1195e8c91ea383d38d05d1c -iv b6f5d0f0dd7146b0e3915ebd2dd078f3
 * ERxV45wkpjJWXs+Mg9m6UyGHHGzBG5/2ytX0j0x3qNPuz5oWyciqkWjkBznLTWxb
* *

* The configuration file will look like the following. *

* *
 * base_url = https://evaluation-dot-authlete.appspot.com
 * service_owner.api_key = etKXFbM0VumfC5j1XD6qGOk3yhHmsdqOILBFFIkDfmw
 * service_owner.api_secret.encrypted = sKzcMU98a8xA5lwR23Crfkyu23klZnTuQlWApyllARpHFv84IItoZFZXj70OCrnF
 * service.api_key = KNiA4bWqj2Ht0CJTqr4DTBgTIXeCskCHQ_vONBeth6M
 * service.api_secret.encrypted = ERxV45wkpjJWXs+Mg9m6UyGHHGzBG5/2ytX0j0x3qNPuz5oWyciqkWjkBznLTWxb
* *

* And to load the configuration file, an {@code AuthletePropertiesConfiguration} * instance needs to be constructed as follows: *

* *
 * String key = "a281ac2de1195e8c91ea383d38d05d1c";
 * String iv  = "b6f5d0f0dd7146b0e3915ebd2dd078f3";
 *
 * {@link AuthleteConfiguration} conf = new {@link #AuthletePropertiesConfiguration(String, String)
 * AuthletePropertiesConfiguration(key, iv)};
* *

* Constructors without {@code file} parameter use {@code "authlete.properties"} * as the name of the configuration file and search the file system and then * the classpath for the file. *

*/ public class AuthletePropertiesConfiguration implements AuthleteConfiguration { /** * The default value of the secret key to decode encrypted property values * ({@code a281ac2de1195e8c91ea383d38d05d1c}). * * @since 1.24 */ public static final String DEFAULT_KEY = "a281ac2de1195e8c91ea383d38d05d1c"; /** * The default value of the initial vector to decode encrypted property values * ({@code b6f5d0f0dd7146b0e3915ebd2dd078f3}). * * @since 1.24 */ public static final String DEFAULT_IV = "b6f5d0f0dd7146b0e3915ebd2dd078f3"; /** * The default value of the name of the configuration file * ({@code authlete.properties}). * * @since 1.24 */ public static final String DEFAULT_FILE = "authlete.properties"; /** * The system property key to specify the name of an Authlete * configuration file ({@code authlete.configuration.file}). * When this system property has a value, it is used as the name * of the configuration file. Otherwise, the default file * ({@code authlete.properties}) is used. * * @since 1.29 */ public static final String SYSTEM_PROPERTY_AUTHLETE_CONFIGURATION_FILE = "authlete.configuration.file"; /** * Property key to specify the base URL ({@code base_url}). */ private static final String PROPERTY_KEY_BASE_URL = "base_url"; /** * Property key to specify the service owner API key * ({@code service_owner.api_key}). */ private static final String PROPERTY_KEY_SERVICE_OWNER_API_KEY = "service_owner.api_key"; /** * Property key to specify the encrypted service owner API secret * ({@code service_owner.api_secret.encrypted}). */ private static final String PROPERTY_KEY_SERVICE_OWNER_API_SECRET_ENCRYPTED = "service_owner.api_secret.encrypted"; /** * Property key to specify the service owner API secret * ({@code service_owner.api_secret}). */ private static final String PROPERTY_KEY_SERVICE_OWNER_API_SECRET = "service_owner.api_secret"; /** * Property key to specify the service owner access token * ({@code service_owner.access_token}). */ private static final String PROPERTY_KEY_SERVICE_OWNER_ACCESS_TOKEN = "service_owner.access_token"; /** * Property key to specify the service API key * ({@code service.api_key}). */ private static final String PROPERTY_KEY_SERVICE_API_KEY = "service.api_key"; /** * Property key to specify the encrypted service API secret * ({@code service.api_secret.encrypted}). */ private static final String PROPERTY_KEY_SERVICE_API_SECRET_ENCRYPTED = "service.api_secret.encrypted"; /** * Property key to specify the service API secret * ({@code service.api_secret}). */ private static final String PROPERTY_KEY_SERVICE_API_SECRET = "service.api_secret"; /** * Property key to specify the service access token * ({@code service.access_token}). */ private static final String PROPERTY_KEY_SERVICE_ACCESS_TOKEN = "service.access_token"; /** * Property key to specify the dpop signing key * ({@code service.dpop_key}). */ private static final String PROPERTY_KEY_DPOP_KEY = "service.dpop_key"; /** * Property key to specify the client's MTLS certificate * ({@code service.client_certificate}). */ private static final String PROPERTY_KEY_CLIENT_CERTIFICATE = "service.client_certificate"; /** * Property key to specify the API version. * ({@code api_version}). */ private static final String PROPERTY_KEY_API_VERSION = "api_version"; /** * The default value of the base URL ({@code https://api.authlete.com}). */ private static final String BASE_URL_DEFAULT = "https://api.authlete.com"; /** * Base URL. */ private String mBaseUrl; /** * Service owner API key. */ private String mServiceOwnerApiKey; /** * Service owner API secret. */ private String mServiceOwnerApiSecret; /** * Service owner access token. */ private String mServiceOwnerAccessToken; /** * Service API key. */ private String mServiceApiKey; /** * Service API secret. */ private String mServiceApiSecret; /** * Service access token. */ private String mServiceAccessToken; /** * DPoP Signing key pair */ private String mDpopKey; /** * Client MTLS certificate. */ private String mClientCertificate; /** * Supported API Version. */ private String mApiVersion; /** * Constructor with a pair of secret key and initial vector to decode * encrypted property values. * *

* This constructor is an alias of {@link #AuthletePropertiesConfiguration( * String, String, String) this}(file, key, iv) where * file is either {@link #DEFAULT_FILE * authlete.properties} or the value of the system property {@link * #SYSTEM_PROPERTY_AUTHLETE_CONFIGURATION_FILE authlete.configuration.file} * if the value is not empty. *

* * @param key * The secret key to decode encrypted property values in hex. * For example, {@code "9543837d590ef25312e7d156a435feda"}. * * @param iv * The initial vector to decode encrypted property values. * For example, {@code "e90ce45e6134d37e0aa2c3c870003639"}. * * @throws IllegalArgumentException *
    *
  • {@code key} is {@code null} *
  • {@code iv} is {@code null} *
* * @throws NumberFormatException *
    *
  • {@code key} is not a valid hex string. *
  • {@code iv} is not a valid hex string. *
*/ public AuthletePropertiesConfiguration(String key, String iv) { this(getFile(), key, iv); } /** * Constructor with a pair of secret key and initial vector to decode * encrypted property values. * *

* This constructor is an alias of {@link #AuthletePropertiesConfiguration( * String, byte[], byte[]) this}(file, key, iv) where * file is either {@link #DEFAULT_FILE * authlete.properties} or the value of the system property {@link * #SYSTEM_PROPERTY_AUTHLETE_CONFIGURATION_FILE authlete.configuration.file} * if the value is not empty. *

* * @param key * The secret key to decode encrypted property values. * * @param iv * The initial vector to decode encrypted property values. * * @throws IllegalArgumentException *
    *
  • {@code key} is {@code null} *
  • {@code iv} is {@code null} *
*/ public AuthletePropertiesConfiguration(byte[] key, byte[] iv) { this(getFile(), key, iv); } /** * Constructor with a configuration file name and a pair of secret key * and initial vector to decode encrypted property values. * * @param file * The name of the configuration file. The file system and then * the classpath are searched for the file. * * @param key * The secret key to decode encrypted property values in hex. * For example, {@code "9543837d590ef25312e7d156a435feda"}. * * @param iv * The initial vector to decode encrypted property values. * For example, {@code "e90ce45e6134d37e0aa2c3c870003639"}. * * @throws IllegalArgumentException *
    *
  • {@code file} is {@code null} *
  • {@code key} is {@code null} *
  • {@code iv} is {@code null} *
* * @throws NumberFormatException *
    *
  • {@code key} is not a valid hex string. *
  • {@code iv} is not a valid hex string. *
*/ public AuthletePropertiesConfiguration(String file, String key, String iv) { this(file, convertHexStringToBytes("key", key), convertHexStringToBytes("iv", iv)); } /** * Constructor with a configuration file name. * *

* This constructor is an alias of {@link #AuthletePropertiesConfiguration( * String, String, String) this}{@code (file, }{@link #DEFAULT_KEY}{@code * , }{@link #DEFAULT_IV}{@code )}. *

* * @param file * The name of the configuration file. The file system and then * the classpath are searched for the file. * * @throws IllegalArgumentException * {@code file} is {@code null}. * * @since 1.24 */ public AuthletePropertiesConfiguration(String file) { this(file, DEFAULT_KEY, DEFAULT_IV); } /** * Constructor with no argument. * *

* This constructor is an alias of {@link #AuthletePropertiesConfiguration( * String, String, String) this}(file, {@link * #DEFAULT_KEY}{@code , }{@link #DEFAULT_IV}{@code )} where * file is either {@link #DEFAULT_FILE * authlete.properties} or the value of the system property {@link * #SYSTEM_PROPERTY_AUTHLETE_CONFIGURATION_FILE authlete.configuration.file} * if the value is not empty. *

* * @since 1.24 */ public AuthletePropertiesConfiguration() { this(getFile(), DEFAULT_KEY, DEFAULT_IV); } /** * Constructor with a configuration file name and a pair of secret key * and initial vector to decode encrypted property values. * * @param file * The name of the configuration file. The file system and then * the classpath are searched for the file. * * @param key * The secret key to decode encrypted property values. * * @param iv * The initial vector to decode encrypted property values. * * @throws IllegalArgumentException *
    *
  • {@code file} is {@code null} *
  • {@code key} is {@code null} *
  • {@code iv} is {@code null} *
*/ public AuthletePropertiesConfiguration(String file, byte[] key, byte[] iv) { // Load the configuration file. TypedProperties props = PropertiesLoader.load(file); // If failed. if (props == null) { // Failed to load the configuration file. String message = String.format("Failed to load '%s'.", file); Logger.getLogger(AuthletePropertiesConfiguration.class.getName()).severe(message); return; } // Base URL of Authlete API. mBaseUrl = props.getString(PROPERTY_KEY_BASE_URL, BASE_URL_DEFAULT); // Service owner API key issued by Authlete. mServiceOwnerApiKey = props.getString(PROPERTY_KEY_SERVICE_OWNER_API_KEY); // Service owner API secret issued by Authlete. String encryptedServiceOwnerApiSecret = props.getString(PROPERTY_KEY_SERVICE_OWNER_API_SECRET_ENCRYPTED); if (encryptedServiceOwnerApiSecret != null) { mServiceOwnerApiSecret = createCipher(key,iv).decrypt(encryptedServiceOwnerApiSecret); } else { mServiceOwnerApiSecret = props.getString(PROPERTY_KEY_SERVICE_OWNER_API_SECRET); } // Service API key issued by Authlete. mServiceApiKey = props.getString(PROPERTY_KEY_SERVICE_API_KEY); // Service API secret issued by Authlete. String encryptedServiceApiSecret = props.getString(PROPERTY_KEY_SERVICE_API_SECRET_ENCRYPTED); if (encryptedServiceApiSecret != null) { mServiceApiSecret = createCipher(key,iv).decrypt(encryptedServiceApiSecret); } else { mServiceApiSecret = props.getString(PROPERTY_KEY_SERVICE_API_SECRET); } mServiceAccessToken = props.getString(PROPERTY_KEY_SERVICE_ACCESS_TOKEN); mServiceOwnerAccessToken = props.getString(PROPERTY_KEY_SERVICE_OWNER_ACCESS_TOKEN); mDpopKey = props.getString(PROPERTY_KEY_DPOP_KEY); mClientCertificate = props.getString(PROPERTY_KEY_CLIENT_CERTIFICATE); mApiVersion = props.getString(PROPERTY_KEY_API_VERSION); } private static String getFile() { // The name of the authlete configuration file specified via the system property. String file = System.getProperty(SYSTEM_PROPERTY_AUTHLETE_CONFIGURATION_FILE); if (file != null && file.length() != 0) { return file; } // The default file name. return DEFAULT_FILE; } private static AESCipher createCipher(byte[] key, byte[] iv) { ensureNonNull("key", key); ensureNonNull("iv", iv); // Create a cipher for AES/CBC/PKCS5Padding + Base64 // (the combination is the default of AECipher()). return new AESCipher().setKey(key, iv); } private static byte[] convertHexStringToBytes(String name, String value) { ensureNonNull(name, value); int len = value.length(); byte[] bytes = new byte[(len + 1) / 2]; for (int i = 0; i < len; ++i) { char c = value.charAt(i); int n = convertHexCharToInt(c); if (i % 2 == 0) { bytes[i / 2] = (byte)((n << 4) & 0xFF); } else { bytes[i / 2] |= (byte)(n & 0xFF); } } return bytes; } private static int convertHexCharToInt(char c) { if ('0' <= c && c <= '9') { return (c - '0'); } else if ('a' <= c && c <= 'f') { return (c - 'a' + 10); } else { return (c - 'A' + 10); } } private static void ensureNonNull(String name, Object value) { if (value == null) { throw new IllegalArgumentException(name + " is null."); } } /** * Get the Authlete API version. */ @Override public String getApiVersion() { return mApiVersion; } /** * Get the base URL. */ @Override public String getBaseUrl() { return mBaseUrl; } /** * Get the service owner API key. */ @Override public String getServiceOwnerApiKey() { return mServiceOwnerApiKey; } /** * Get the service owner API secret. */ @Override public String getServiceOwnerApiSecret() { return mServiceOwnerApiSecret; } @Override public String getServiceOwnerAccessToken() { return mServiceOwnerAccessToken; } /** * Get the service API key. */ @Override public String getServiceApiKey() { return mServiceApiKey; } /** * Get the service API secret. */ @Override public String getServiceApiSecret() { return mServiceApiSecret; } @Override public String getServiceAccessToken() { return mServiceAccessToken; } @Override public String getDpopKey() { return mDpopKey; } @Override public String getClientCertificate() { return mClientCertificate; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy