3d15b09dbed3484e9874130f6bb91d4e56a8612e
[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
398         public void set(LogIt logit) {
399                 logIt = logit;
400         }
401 }