Collection syntax change because of Sonar
[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 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                                 if(trim!=value) { // Yes, I want OBJECT equals
213                                         props.setProperty((String)es.getKey(), trim);
214                                 }
215                         }
216                 }
217                 // Reset Symm if Keyfile Changes:
218                 String newKeyFile = props.getProperty(Config.CADI_KEYFILE);
219                 if((prevKeyFile!=null && newKeyFile!=null) || (newKeyFile!=null && !newKeyFile.equals(prevKeyFile))) {
220                         try {
221                                 symm = Symm.obtain(this);
222                         } catch (CadiException e) {
223                                 System.err.append("FATAL ERROR: Cannot obtain Key Information.");
224                                 e.printStackTrace(System.err);
225                                 System.exit(1);
226                         }
227
228                         prevKeyFile=newKeyFile;
229                 }
230                 
231                 String loglevel = props.getProperty(Config.CADI_LOGLEVEL);
232                 if(loglevel!=null) {
233                         try {
234                                 level=Level.valueOf(loglevel).maskOf();
235                         } catch (IllegalArgumentException e) {
236                                 printf(Level.ERROR,"%s=%s is an Invalid Log Level",Config.CADI_LOGLEVEL,loglevel);
237                         }
238                 }
239                 
240                 specialConversions();
241         }
242         
243         @Override
244         public void load(InputStream is) throws IOException {
245                 props.load(is);
246                 load(props.getProperty(Config.CADI_PROP_FILES));
247         }
248
249         @Override
250         public void log(Level level, Object ... elements) {
251                 if(willLog(level)) {
252                         logIt.push(level,elements);
253                 }
254         }
255
256         protected StringBuilder buildMsg(Level level, Object[] elements) {
257                 return buildMsg(name,iso8601,level,elements);
258         }
259
260         public static StringBuilder buildMsg(final String name, final SimpleDateFormat sdf, Level level, Object[] elements) { 
261                 StringBuilder sb = new StringBuilder(sdf.format(new Date()));
262                 sb.append(' ');
263                 sb.append(level.name());
264                 sb.append(" [");
265                 sb.append(name);
266                 
267                 int end = elements.length;
268                 if(end<=0) {
269                         sb.append("] ");
270                 } else {
271                         int idx = 0;
272                         if(elements[idx] instanceof Integer) {
273                                 sb.append('-');
274                                 sb.append(elements[idx]);
275                                 ++idx;
276                         }
277                         sb.append("] ");
278                         String s;
279                         boolean first = true;
280                         for(Object o : elements) {
281                                 if(o!=null) {
282                                         s=o.toString();
283                                         if(first) {
284                                                 first = false;
285                                         } else {
286                                                 int l = s.length();
287                                                 if(l>0) {
288                                                         switch(s.charAt(l-1)) {
289                                                                 case ' ':
290                                                                         break;
291                                                                 default:
292                                                                         sb.append(' ');
293                                                         }
294                                                 }
295                                         }
296                                         sb.append(s);
297                                 }
298                         }
299                 }
300                 return sb;
301         }
302
303         @Override
304         public void log(Exception e, Object... elements) {
305                 log(Level.ERROR,e.getMessage(),elements);
306                 e.printStackTrace(System.err);
307         }
308
309         @Override
310         public void printf(Level level, String fmt, Object... elements) {
311                 if(willLog(level)) {
312                         log(level,String.format(fmt, elements));
313                 }
314         }
315
316         @Override
317         public void setLogLevel(Level level) {
318                 this.level = level.maskOf();
319         }
320
321         @Override
322         public boolean willLog(Level level) {
323                 return level.inMask(this.level);
324         }
325
326         @Override
327         public ClassLoader classLoader() {
328                 return ClassLoader.getSystemClassLoader();
329         }
330
331         @Override
332         public String getProperty(String tag, String def) {
333                 return props.getProperty(tag,def);
334         }
335
336         @Override
337         public String decrypt(String encrypted, boolean anytext) throws IOException {
338                 return (encrypted!=null && (anytext==true || encrypted.startsWith(Symm.ENC)))
339                         ? symm.depass(encrypted)
340                         : encrypted;
341         }
342         
343         public String encrypt(String unencrypted) throws IOException {
344                 return Symm.ENC+symm.enpass(unencrypted);
345         }
346
347         //////////////////
348         // Additional
349         //////////////////
350         public String getProperty(String tag) {
351                 return props.getProperty(tag);
352         }
353         
354
355         public Properties getProperties() {
356                 return props;
357         }
358
359         public void setProperty(String tag, String value) {
360                 if(value!=null) {
361                         props.put(tag, value);
362                         if(Config.CADI_KEYFILE.equals(tag)) {
363                                 // reset decryption too
364                                 try {
365                                         symm = Symm.obtain(this);
366                                 } catch (CadiException e) {
367                                         System.err.append("FATAL ERROR: Cannot obtain Key Information.");
368                                         e.printStackTrace(System.err);
369                                         System.exit(1);
370                                 }
371                         }
372                 }
373         }
374
375         public interface LogIt {
376                 public void push(Level level, Object ... elements) ;
377         }
378         
379         private class StreamLogIt implements LogIt {
380                 private PrintStream ps;
381                 
382                 public StreamLogIt(PrintStream ps) {
383                         this.ps = ps;
384                 }
385                 @Override
386                 public void push(Level level, Object ... elements) {
387                         ps.println(buildMsg(level,elements));
388                         ps.flush();
389                 }
390                 
391         }
392
393         public void set(LogIt logit) {
394                 logIt = logit;
395         }
396 }