/* * * * Copyright 2016 OrientDB LTD * * * * 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. * * * * For more information: http://www.orientdb.com * */ package com.orientechnologies.orient.core.security.symmetrickey; import com.orientechnologies.common.log.OLogManager; import com.orientechnologies.orient.core.config.OGlobalConfiguration; import com.orientechnologies.orient.core.exception.OSecurityException; import com.orientechnologies.orient.core.record.impl.ODocument; import com.orientechnologies.orient.core.security.OCredentialInterceptor; import com.orientechnologies.orient.core.serialization.OBase64Utils; import java.net.URISyntaxException; import java.net.URI; import java.security.Principal; import java.security.PrivilegedAction; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import javax.security.auth.Subject; /** * Provides a symmetric key credential interceptor. * * The "password" parameter should be a JSON document specifying "keyAlgorithm" and * "key", "keyFile", or "keyStore". * * The method getPassword() will return a Base64-encoded JSON document with the encrypted * "username" as its payload. * * @author S. Colin Leister * */ public class OSymmetricKeyCI implements OCredentialInterceptor { private String username; private String encodedJSON = ""; public String getUsername() { return this.username; } public String getPassword() { return this.encodedJSON; } /** * The usual password field should be a JSON representation. */ public void intercept(final String url, final String username, final String password) throws OSecurityException { if(username == null || username.isEmpty()) throw new OSecurityException("OSymmetricKeyCI username is not valid!"); if(password == null || password.isEmpty()) throw new OSecurityException("OSymmetricKeyCI password is not valid!"); this.username = username; // These are all used as defaults if the JSON document is missing any fields. // Defaults to "AES". String algorithm = OGlobalConfiguration.CLIENT_CI_KEYALGORITHM.getValueAsString(); // Defaults to "AES/CBC/PKCS5Padding". String transform = OGlobalConfiguration.CLIENT_CI_CIPHERTRANSFORM.getValueAsString(); String keystoreFile = OGlobalConfiguration.CLIENT_CI_KEYSTORE_FILE.getValueAsString(); String keystorePassword = OGlobalConfiguration.CLIENT_CI_KEYSTORE_PASSWORD.getValueAsString(); ODocument jsonDoc = null; try { jsonDoc = new ODocument().fromJSON(password, "noMap"); } catch(Exception ex) { throw new OSecurityException("OSymmetricKeyCI.intercept() Exception: " + ex.getMessage()); } // Override algorithm and transform, if they exist in the JSON document. if(jsonDoc.containsField("algorithm")) algorithm = jsonDoc.field("algorithm"); if(jsonDoc.containsField("transform")) transform = jsonDoc.field("transform"); // Just in case the default configuration gets changed, check it. if(transform == null || transform.isEmpty()) throw new OSecurityException("OSymmetricKeyCI.intercept() cipher transformation is required"); // If the algorithm is not set, either as a default in the global configuration or in the JSON document, // then determine the algorithm from the cipher transformation. if(algorithm == null) algorithm = OSymmetricKey.separateAlgorithm(transform); OSymmetricKey key = null; // "key" has priority over "keyFile" and "keyStore". if(jsonDoc.containsField("key")) { final String base64Key = jsonDoc.field("key"); key = OSymmetricKey.fromString(algorithm, base64Key); key.setDefaultCipherTransform(transform); } else // "keyFile" has priority over "keyStore". if(jsonDoc.containsField("keyFile")) { key = OSymmetricKey.fromFile(algorithm, (String)jsonDoc.field("keyFile")); key.setDefaultCipherTransform(transform); } else if(jsonDoc.containsField("keyStore")) { ODocument ksDoc = jsonDoc.field("keyStore"); if(ksDoc.containsField("file")) keystoreFile = ksDoc.field("file"); if(keystoreFile == null || keystoreFile.isEmpty()) throw new OSecurityException("OSymmetricKeyCI.intercept() keystore file is required"); // Specific to Keystore, but override if present in the JSON document. if(ksDoc.containsField("password")) keystorePassword = ksDoc.field("password"); String keyAlias = ksDoc.field("keyAlias"); if(keyAlias == null || keyAlias.isEmpty()) throw new OSecurityException("OSymmetricKeyCI.intercept() keystore key alias is required"); // keyPassword may be null. String keyPassword = ksDoc.field("keyPassword"); // keystorePassword may be null. key = OSymmetricKey.fromKeystore(keystoreFile, keystorePassword, keyAlias, keyPassword); key.setDefaultCipherTransform(transform); } else { throw new OSecurityException("OSymmetricKeyCI.intercept() No suitable symmetric key property exists"); } // This should never happen, but... if(key == null) throw new OSecurityException("OSymmetricKeyCI.intercept() OSymmetricKey is null"); encodedJSON = key.encrypt(transform, username); } }