/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.hadoop.gateway.services.security.impl; import org.apache.commons.codec.binary.Base64; import org.apache.hadoop.gateway.i18n.GatewaySpiMessages; import org.apache.hadoop.gateway.i18n.messages.MessagesFactory; import org.apache.hadoop.gateway.services.security.KeystoreServiceException; import org.apache.hadoop.gateway.services.security.MasterService; import javax.crypto.spec.SecretKeySpec; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.security.Key; import java.security.KeyPair; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; public class BaseKeystoreService { private static GatewaySpiMessages LOG = MessagesFactory.get( GatewaySpiMessages.class ); protected MasterService masterService; protected String keyStoreDir; private static KeyStore loadKeyStore(final File keyStoreFile, final char[] masterPassword, String storeType) throws CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException { final KeyStore keyStore = KeyStore.getInstance(storeType); if ( keyStoreFile.exists() ) { final FileInputStream input = new FileInputStream( keyStoreFile ); try { keyStore.load( input, masterPassword ); } finally { input.close(); } } else { keyStore.load( null, masterPassword ); } return keyStore; } private static FileOutputStream createKeyStoreFile( String fileName ) throws IOException { File file = new File( fileName ); if( file.exists() ) { if( file.isDirectory() ) { throw new IOException( file.getAbsolutePath() ); } else if( !file.canWrite() ) { throw new IOException( file.getAbsolutePath() ); } } else { File dir = file.getParentFile(); if( !dir.exists() ) { if( !dir.mkdirs() ) { throw new IOException( file.getAbsolutePath() ); } } } FileOutputStream stream = new FileOutputStream( file ); return stream; } protected void createKeystore(String filename, String keystoreType) throws KeystoreServiceException { try { FileOutputStream out = createKeyStoreFile( filename ); KeyStore ks = KeyStore.getInstance(keystoreType); ks.load( null, null ); ks.store( out, masterService.getMasterSecret() ); out.close(); } catch (KeyStoreException e) { LOG.failedToCreateKeystore( filename, keystoreType, e ); throw new KeystoreServiceException(e); } catch (NoSuchAlgorithmException e) { LOG.failedToCreateKeystore( filename, keystoreType, e ); throw new KeystoreServiceException(e); } catch (CertificateException e) { LOG.failedToCreateKeystore( filename, keystoreType, e ); throw new KeystoreServiceException(e); } catch (FileNotFoundException e) { LOG.failedToCreateKeystore( filename, keystoreType, e ); throw new KeystoreServiceException(e); } catch (IOException e) { LOG.failedToCreateKeystore( filename, keystoreType, e ); throw new KeystoreServiceException(e); } } protected boolean isKeystoreAvailable(final File keyStoreFile, String storeType) throws KeyStoreException, IOException { if ( keyStoreFile.exists() ) { FileInputStream input = null; try { final KeyStore keyStore = KeyStore.getInstance(storeType); input = new FileInputStream( keyStoreFile ); keyStore.load( input, masterService.getMasterSecret() ); return true; } catch (NoSuchAlgorithmException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); } catch (CertificateException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); } catch (IOException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); throw e; } catch (KeyStoreException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); throw e; } finally { try { if ( input != null ) { input.close(); } } catch (IOException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); } } } return false; } protected KeyStore getKeystore(final File keyStoreFile, String storeType) throws KeystoreServiceException { KeyStore credStore = null; try { credStore = loadKeyStore( keyStoreFile, masterService.getMasterSecret(), storeType); } catch (CertificateException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); throw new KeystoreServiceException(e); } catch (KeyStoreException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); throw new KeystoreServiceException(e); } catch (NoSuchAlgorithmException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); throw new KeystoreServiceException(e); } catch (IOException e) { LOG.failedToLoadKeystore( keyStoreFile.getName(), storeType, e ); throw new KeystoreServiceException(e); } return credStore; } public BaseKeystoreService() { super(); } protected void addCredential(String alias, String value, KeyStore ks) { if (ks != null) { try { final Key key = new SecretKeySpec(value.getBytes("UTF8"), "AES"); ks.setKeyEntry( alias, key, masterService.getMasterSecret(), null); } catch (KeyStoreException e) { LOG.failedToAddCredential(e); } catch (IOException e) { LOG.failedToAddCredential(e); } } } public void removeCredential(String alias, KeyStore ks) { if (ks != null) { try { if (ks.containsAlias(alias)) { ks.deleteEntry(alias); } } catch (KeyStoreException e) { LOG.failedToRemoveCredential(e); } } } protected char[] getCredential(String alias, char[] credential, KeyStore ks) { if (ks != null) { try { credential = new String(ks.getKey(alias, masterService.getMasterSecret()).getEncoded()).toCharArray(); } catch (UnrecoverableKeyException e) { LOG.failedToGetCredential(e); } catch (KeyStoreException e) { LOG.failedToGetCredential(e); } catch (NoSuchAlgorithmException e) { LOG.failedToGetCredential(e); } } return credential; } protected void writeCertificateToFile( Certificate cert, final File file ) throws CertificateEncodingException, IOException { byte[] bytes = cert.getEncoded(); Base64 encoder = new Base64( 76, "\n".getBytes( "ASCII" ) ); try( final FileOutputStream out = new FileOutputStream( file ) ) { out.write( "-----BEGIN CERTIFICATE-----\n".getBytes( "ASCII" ) ); out.write( encoder.encodeToString( bytes ).getBytes( "ASCII" ) ); out.write( "-----END CERTIFICATE-----\n".getBytes( "ASCII" ) ); } } protected void writeKeystoreToFile(final KeyStore keyStore, final File file) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { // TODO: backup the keystore on disk before attempting a write and restore on failure try( final FileOutputStream out = new FileOutputStream(file) ) { keyStore.store( out, masterService.getMasterSecret() ); } } public void setMasterService(MasterService ms) { this.masterService = ms; } }