1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.hadoop.hbase.io.crypto;
18
19 import java.io.BufferedInputStream;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.InputStream;
23 import java.io.IOException;
24 import java.net.URI;
25 import java.net.URISyntaxException;
26 import java.net.URLDecoder;
27 import java.security.Key;
28 import java.security.KeyStore;
29 import java.security.KeyStoreException;
30 import java.security.NoSuchAlgorithmException;
31 import java.security.UnrecoverableKeyException;
32 import java.security.cert.CertificateException;
33 import java.util.Locale;
34 import java.util.Properties;
35
36 import org.apache.hadoop.hbase.classification.InterfaceAudience;
37 import org.apache.hadoop.hbase.classification.InterfaceStability;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 @InterfaceAudience.Public
74 @InterfaceStability.Evolving
75 public class KeyStoreKeyProvider implements KeyProvider {
76
77 protected KeyStore store;
78 protected char[] password;
79 protected Properties passwordFile;
80
81 protected void processParameter(String name, String value) throws IOException {
82 if (name.equalsIgnoreCase(KeyProvider.PASSWORD)) {
83 password = value.toCharArray();
84 }
85 if (name.equalsIgnoreCase(KeyProvider.PASSWORDFILE)) {
86 Properties p = new Properties();
87 InputStream in = new BufferedInputStream(new FileInputStream(new File(value)));
88 try {
89 p.load(in);
90 passwordFile = p;
91 } finally {
92 in.close();
93 }
94 }
95 }
96
97 protected void processParameters(URI uri) throws IOException {
98 String params = uri.getQuery();
99 if (params == null || params.isEmpty()) {
100 return;
101 }
102 do {
103 int nameStart = 0;
104 int nameEnd = params.indexOf('=');
105 if (nameEnd == -1) {
106 throw new RuntimeException("Invalid parameters: '" + params + "'");
107 }
108 int valueStart = nameEnd + 1;
109 int valueEnd = params.indexOf('&');
110 if (valueEnd == -1) {
111 valueEnd = params.length();
112 }
113 String name = URLDecoder.decode(params.substring(nameStart, nameEnd), "UTF-8");
114 String value = URLDecoder.decode(params.substring(valueStart, valueEnd), "UTF-8");
115 processParameter(name, value);
116 params = params.substring(valueEnd, params.length());
117 } while (!params.isEmpty());
118 }
119
120 protected void load(URI uri) throws IOException {
121 String path = uri.getPath();
122 if (path == null || path.isEmpty()) {
123 throw new RuntimeException("KeyProvider parameters should specify a path");
124 }
125 InputStream is = new FileInputStream(new File(path));
126 try {
127 store.load(is, password);
128 } catch (NoSuchAlgorithmException e) {
129 throw new RuntimeException(e);
130 } catch (CertificateException e) {
131 throw new RuntimeException(e);
132 } finally {
133 is.close();
134 }
135 }
136
137 @Override
138 public void init(String params) {
139 try {
140 URI uri = new URI(params);
141 String storeType = uri.getScheme();
142 if (storeType == null || storeType.isEmpty()) {
143 throw new RuntimeException("KeyProvider scheme should specify KeyStore type");
144 }
145
146 store = KeyStore.getInstance(storeType.toUpperCase(Locale.ROOT));
147 processParameters(uri);
148 load(uri);
149 } catch (URISyntaxException e) {
150 throw new RuntimeException(e);
151 } catch (KeyStoreException e) {
152 throw new RuntimeException(e);
153 } catch (IOException e) {
154 throw new RuntimeException(e);
155 }
156 }
157
158 protected char[] getAliasPassword(String alias) {
159 if (password != null) {
160 return password;
161 }
162 if (passwordFile != null) {
163 String p = passwordFile.getProperty(alias);
164 if (p != null) {
165 return p.toCharArray();
166 }
167 }
168 return null;
169 }
170
171 @Override
172 public Key getKey(String alias) {
173 try {
174 return store.getKey(alias, getAliasPassword(alias));
175 } catch (UnrecoverableKeyException e) {
176 throw new RuntimeException(e);
177 } catch (KeyStoreException e) {
178 throw new RuntimeException(e);
179 } catch (NoSuchAlgorithmException e) {
180 throw new RuntimeException(e);
181 }
182 }
183
184 @Override
185 public Key[] getKeys(String[] aliases) {
186 Key[] result = new Key[aliases.length];
187 for (int i = 0; i < aliases.length; i++) {
188 result[i] = getKey(aliases[i]);
189 }
190 return result;
191 }
192
193 }