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