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