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