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