bd1ad72d1e31d17797d0c39b0ba2ee8b5f03f10a
[aaf/authz.git] / cadi / core / src / main / java / org / onap / aaf / cadi / PropAccess.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.cadi;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.PrintStream;
29 import java.text.SimpleDateFormat;
30 import java.util.ArrayList;
31 import java.util.Date;
32 import java.util.List;
33 import java.util.Map.Entry;
34
35 import org.onap.aaf.cadi.config.Config;
36 import org.onap.aaf.cadi.config.SecurityInfo;
37
38 import java.util.Properties;
39
40 public class PropAccess implements Access {
41         // Sonar says cannot be static... it's ok.  not too many PropAccesses created.
42         private final SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
43
44         public static Level DEFAULT = Level.AUDIT;
45         
46         private Symm symm;
47         private int level;
48         private Properties props;
49         private List<String> recursionProtection = null;
50         private LogIt logIt;
51         private String name;
52
53         public PropAccess() {
54                 logIt = new StreamLogIt(System.out);
55                 init(null);
56         }
57         
58         /**
59          * This Constructor soly exists to instantiate Servlet Context Based Logging that will call "init" later.
60          * @param sc
61          */
62         protected PropAccess(Object o) {
63                 logIt = new StreamLogIt(System.out);
64                 props = new Properties();
65         }
66         
67         public PropAccess(String ... args) {
68                 this(System.out,args);
69         }
70         
71         public PropAccess(PrintStream ps, String[] args) {
72                 logIt = new StreamLogIt(ps==null?System.out:ps);
73                 Properties nprops=new Properties();
74                 int eq;
75                 for(String arg : args) {
76                         if((eq=arg.indexOf('='))>0) {
77                                 nprops.setProperty(arg.substring(0, eq),arg.substring(eq+1));
78                         }
79                 }
80                 init(nprops);
81         }
82         
83         public PropAccess(LogIt logit, String[] args) {
84                 logIt = logit;
85         }
86         
87         public PropAccess(Properties p) {
88                 this(System.out,p);
89         }
90         
91         public PropAccess(PrintStream ps, Properties p) {
92                 logIt = new StreamLogIt(ps==null?System.out:ps);
93                 init(p);
94         }
95         
96         protected void init(Properties p) {
97                 // Make sure these two are set before any changes in Logging
98                 name = "cadi";
99                 level=DEFAULT.maskOf();
100                 
101                 props = new Properties();
102                 // First, load related System Properties
103                 for(Entry<Object,Object> es : System.getProperties().entrySet()) {
104                         String key = es.getKey().toString();
105                         for(String start : new String[] {"cadi_","aaf_","cm_"}) {
106                                 if(key.startsWith(start)) {
107                                         props.put(key, es.getValue());
108                                 }
109                         }                       
110                 }
111                 // Second, overlay or fill in with Passed in Props
112                 if(p!=null) {
113                         props.putAll(p);
114                 }
115                 
116                 // Third, load any Chained Property Files
117                 load(props.getProperty(Config.CADI_PROP_FILES));
118                 
119                 String sLevel = props.getProperty(Config.CADI_LOGLEVEL); 
120                 if(sLevel!=null) {
121                         level=Level.valueOf(sLevel).maskOf(); 
122                 }
123                 // Setup local Symmetrical key encryption
124                 if(symm==null) {
125                         try {
126                                 symm = Symm.obtain(this);
127                         } catch (CadiException e) {
128                                 System.err.append("FATAL ERROR: Cannot obtain Key Information.");
129                                 e.printStackTrace(System.err);
130                                 System.exit(1);
131                         }
132                 }
133                 
134                 name = props.getProperty(Config.CADI_LOGNAME, name);
135                 
136                 specialConversions();
137         }
138
139         private void specialConversions() {
140                 // Critical - if no Security Protocols set, then set it.  We'll just get messed up if not
141                 if(props.get(Config.CADI_PROTOCOLS)==null) {
142                         props.setProperty(Config.CADI_PROTOCOLS, SecurityInfo.HTTPS_PROTOCOLS_DEFAULT);
143                 }
144                 
145                 Object temp;
146                 temp=props.get(Config.CADI_PROTOCOLS);
147                 if(props.get(Config.HTTPS_PROTOCOLS)==null && temp!=null) {
148                         props.put(Config.HTTPS_PROTOCOLS, temp);
149                 }
150                 
151                 if(temp!=null) {
152                         if("1.7".equals(System.getProperty("java.specification.version")) 
153                                         && (temp==null || (temp instanceof String && ((String)temp).contains("TLSv1.2")))) {
154                                 System.setProperty(Config.HTTPS_CIPHER_SUITES, Config.HTTPS_CIPHER_SUITES_DEFAULT);
155                         }
156                 }
157         }
158
159         private void load(String cadi_prop_files) {
160                 if(cadi_prop_files==null) {
161                         return;
162                 }
163                 String prevKeyFile = props.getProperty(Config.CADI_KEYFILE);
164                 int prev = 0, end = cadi_prop_files.length();
165                 int idx;
166                 String filename;
167                 while(prev<end) {
168                         idx = cadi_prop_files.indexOf(File.pathSeparatorChar,prev);
169                         if(idx<0) {
170                                 idx = end;
171                         }
172                         File file = new File(filename=cadi_prop_files.substring(prev,idx));
173                         if(file.exists()) {
174                                 printf(Level.INIT,"Loading CADI Properties from %s",file.getAbsolutePath());
175                                 try {
176                                         FileInputStream fis = new FileInputStream(file);
177                                         try {
178                                                 props.load(fis);
179                                                 // Recursively Load
180                                                 String chainProp = props.getProperty(Config.CADI_PROP_FILES);
181                                                 if(chainProp!=null) {
182                                                         if(recursionProtection==null) {
183                                                                 recursionProtection = new ArrayList<String>();
184                                                                 recursionProtection.add(cadi_prop_files);
185                                                         }
186                                                         if(!recursionProtection.contains(chainProp)) {
187                                                                 recursionProtection.add(chainProp);
188                                                                 load(chainProp); // recurse
189                                                         }
190                                                 }
191                                         } finally {
192                                                 fis.close();
193                                         }
194                                 } catch (Exception e) {
195                                         log(e,filename,"cannot be opened");
196                                 }
197                         } else {
198                                 printf(Level.WARN,"Warning: recursive CADI Property %s does not exist",file.getAbsolutePath());
199                         }
200                         prev = idx+1;
201                 }
202                 
203                 // Trim 
204                 for(Entry<Object, Object> es : props.entrySet()) {
205                         Object value = es.getValue();
206                         if(value instanceof String) {
207                                 String trim = ((String)value).trim();
208                                 if(trim!=value) { // Yes, I want OBJECT equals
209                                         props.setProperty((String)es.getKey(), trim);
210                                 }
211                         }
212                 }
213                 // Reset Symm if Keyfile Changes:
214                 String newKeyFile = props.getProperty(Config.CADI_KEYFILE);
215                 if((prevKeyFile!=null && newKeyFile!=null) || (newKeyFile!=null && !newKeyFile.equals(prevKeyFile))) {
216                         try {
217                                 symm = Symm.obtain(this);
218                         } catch (CadiException e) {
219                                 System.err.append("FATAL ERROR: Cannot obtain Key Information.");
220                                 e.printStackTrace(System.err);
221                                 System.exit(1);
222                         }
223
224                         prevKeyFile=newKeyFile;
225                 }
226                 
227                 String loglevel = props.getProperty(Config.CADI_LOGLEVEL);
228                 if(loglevel!=null) {
229                         try {
230                                 level=Level.valueOf(loglevel).maskOf();
231                         } catch (IllegalArgumentException e) {
232                                 printf(Level.ERROR,"%s=%s is an Invalid Log Level",Config.CADI_LOGLEVEL,loglevel);
233                         }
234                 }
235                 
236                 specialConversions();
237         }
238         
239         @Override
240         public void load(InputStream is) throws IOException {
241                 props.load(is);
242                 load(props.getProperty(Config.CADI_PROP_FILES));
243         }
244
245         @Override
246         public void log(Level level, Object ... elements) {
247                 if(willLog(level)) {
248                         logIt.push(level,elements);
249                 }
250         }
251         
252         protected StringBuilder buildMsg(Level level, Object[] elements) {
253                 StringBuilder sb = new StringBuilder(iso8601.format(new Date()));
254                 sb.append(' ');
255                 sb.append(level.name());
256                 sb.append(" [");
257                 sb.append(name);
258                 
259                 int end = elements.length;
260                 if(end<=0) {
261                         sb.append("] ");
262                 } else {
263                         int idx = 0;
264                         if(elements[idx] instanceof Integer) {
265                                 sb.append('-');
266                                 sb.append(elements[idx]);
267                                 ++idx;
268                         }
269                         sb.append("] ");
270                         String s;
271                         boolean first = true;
272                         for(Object o : elements) {
273                                 if(o!=null) {
274                                         s=o.toString();
275                                         if(first) {
276                                                 first = false;
277                                         } else {
278                                                 int l = s.length();
279                                                 if(l>0) {
280                                                         switch(s.charAt(l-1)) {
281                                                                 case ' ':
282                                                                         break;
283                                                                 default:
284                                                                         sb.append(' ');
285                                                         }
286                                                 }
287                                         }
288                                         sb.append(s);
289                                 }
290                         }
291                 }
292                 return sb;
293         }
294
295         @Override
296         public void log(Exception e, Object... elements) {
297                 log(Level.ERROR,e.getMessage(),elements);
298                 e.printStackTrace(System.err);
299         }
300
301         @Override
302         public void printf(Level level, String fmt, Object... elements) {
303                 if(willLog(level)) {
304                         log(level,String.format(fmt, elements));
305                 }
306         }
307
308         @Override
309         public void setLogLevel(Level level) {
310                 this.level = level.maskOf();
311         }
312
313         @Override
314         public boolean willLog(Level level) {
315                 return level.inMask(this.level);
316         }
317
318         @Override
319         public ClassLoader classLoader() {
320                 return ClassLoader.getSystemClassLoader();
321         }
322
323         @Override
324         public String getProperty(String tag, String def) {
325                 return props.getProperty(tag,def);
326         }
327
328         @Override
329         public String decrypt(String encrypted, boolean anytext) throws IOException {
330                 return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))
331                         ? symm.depass(encrypted)
332                         : encrypted;
333         }
334         
335         public String encrypt(String unencrypted) throws IOException {
336                 return Symm.ENC+symm.enpass(unencrypted);
337         }
338
339         //////////////////
340         // Additional
341         //////////////////
342         public String getProperty(String tag) {
343                 return props.getProperty(tag);
344         }
345         
346
347         public Properties getProperties() {
348                 return props;
349         }
350
351         public void setProperty(String tag, String value) {
352                 if(value!=null) {
353                         props.put(tag, value);
354                         if(Config.CADI_KEYFILE.equals(tag)) {
355                                 // reset decryption too
356                                 try {
357                                         symm = Symm.obtain(this);
358                                 } catch (CadiException e) {
359                                         System.err.append("FATAL ERROR: Cannot obtain Key Information.");
360                                         e.printStackTrace(System.err);
361                                         System.exit(1);
362                                 }
363                         }
364                 }
365         }
366
367         public interface LogIt {
368                 public void push(Level level, Object ... elements) ;
369         }
370         
371         private class StreamLogIt implements LogIt {
372                 private PrintStream ps;
373                 
374                 public StreamLogIt(PrintStream ps) {
375                         this.ps = ps;
376                 }
377                 @Override
378                 public void push(Level level, Object ... elements) {
379                         ps.println(buildMsg(level,elements));
380                         ps.flush();
381                 }
382                 
383         }
384
385         public void set(LogIt logit) {
386                 logIt = logit;
387         }
388 }