b2043f071841fc7eeff5a36c1316b5439b7f68be
[aaf/authz.git] / auth / auth-batch / src / main / java / org / onap / aaf / auth / Batch.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.auth;
23
24 import java.io.File;
25 import java.io.FileInputStream;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.PrintStream;
30 import java.lang.reflect.Constructor;
31 import java.net.InetAddress;
32 import java.net.URL;
33 import java.net.UnknownHostException;
34 import java.nio.ByteBuffer;
35 import java.text.SimpleDateFormat;
36 import java.util.GregorianCalendar;
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.Set;
40 import java.util.TimeZone;
41
42 import org.apache.log4j.Logger;
43 import org.onap.aaf.auth.common.Define;
44 import org.onap.aaf.auth.dao.CassAccess;
45 import org.onap.aaf.auth.dao.cass.RoleDAO;
46 import org.onap.aaf.auth.dao.cass.UserRoleDAO;
47 import org.onap.aaf.auth.dao.hl.Question;
48 import org.onap.aaf.auth.env.AuthzEnv;
49 import org.onap.aaf.auth.env.AuthzTrans;
50 import org.onap.aaf.auth.layer.Result;
51 import org.onap.aaf.auth.org.Organization;
52 import org.onap.aaf.auth.org.Organization.Identity;
53 import org.onap.aaf.auth.org.OrganizationException;
54 import org.onap.aaf.auth.org.OrganizationFactory;
55 import org.onap.aaf.cadi.PropAccess;
56 import org.onap.aaf.misc.env.APIException;
57 import org.onap.aaf.misc.env.Env;
58 import org.onap.aaf.misc.env.StaticSlot;
59 import org.onap.aaf.misc.env.TimeTaken;
60 import org.onap.aaf.misc.env.impl.Log4JLogTarget;
61 import org.onap.aaf.misc.env.log4j.LogFileNamer;
62
63 import com.datastax.driver.core.Cluster;
64 import com.datastax.driver.core.ResultSet;
65 import com.datastax.driver.core.Row;
66 import com.datastax.driver.core.Session;
67 import com.datastax.driver.core.Statement;
68
69 public abstract class Batch {
70
71         private static String rootNs;
72
73         private static StaticSlot ssargs;
74
75         protected static final String STARS = "*****";
76
77     protected final Cluster cluster; 
78     protected static AuthzEnv env;
79     protected static Session session;
80     protected static Logger aspr;
81     protected static Set<String> specialNames;
82     protected static boolean dryRun; 
83         protected static String batchEnv;
84
85         public static final String CASS_ENV = "CASS_ENV";
86         public static final String LOG_DIR = "LOG_DIR";
87     protected static final String PUNT="punt";
88     protected static final String MAX_EMAILS="MAX_EMAILS";
89     protected static final String VERSION="VERSION";
90     public static final String GUI_URL="GUI_URL";
91     
92     protected static final String ORA_URL="ora_url";
93     protected static final String ORA_PASSWORD="ora_password";
94         protected final Organization org;
95
96
97     
98     protected Batch(AuthzEnv env) throws APIException, IOException, OrganizationException {
99         // Be able to change Environments
100         // load extra properties, i.e.
101         // PERF.cassandra.clusters=....
102         batchEnv = env.getProperty(CASS_ENV);
103         if(batchEnv != null) {
104                 batchEnv = batchEnv.trim();
105                 env.info().log("Redirecting to ",batchEnv,"environment");
106                 String str;
107                 for(String key : new String[]{
108                                 CassAccess.CASSANDRA_CLUSTERS,
109                                 CassAccess.CASSANDRA_CLUSTERS_PORT,
110                                 CassAccess.CASSANDRA_CLUSTERS_USER_NAME,
111                                 CassAccess.CASSANDRA_CLUSTERS_PASSWORD,
112                                 VERSION,GUI_URL,PUNT,MAX_EMAILS,
113                                 LOG_DIR,
114                                 "SPECIAL_NAMES"
115                                 }) {
116                         if((str = env.getProperty(batchEnv+'.'+key))!=null) {
117                             env.setProperty(key, str);
118                         }
119                 }
120         }
121
122         // Setup for Dry Run
123         cluster = CassAccess.cluster(env,batchEnv);
124         env.info().log("cluster name - ",cluster.getClusterName());
125         String dryRunStr = env.getProperty( "DRY_RUN" );
126         if ( dryRunStr == null || "false".equals(dryRunStr.trim()) ) {
127                     dryRun = false;
128                 } else {
129             dryRun = true;
130             env.info().log("dryRun set to TRUE");
131         }
132
133                 org = OrganizationFactory.init(env);
134                 org.setTestMode(dryRun);
135
136                 // Special names to allow behaviors beyond normal rules
137         specialNames = new HashSet<>();
138         String names = env.getProperty( "SPECIAL_NAMES" );
139         if ( names != null )
140         {
141             env.info().log("Loading SPECIAL_NAMES");
142             for (String s :names.split(",") )
143             {
144                 env.info().log("\tspecial: " + s );
145                 specialNames.add( s.trim() );
146             }
147         }
148     }
149
150     protected abstract void run(AuthzTrans trans);
151     protected abstract void _close(AuthzTrans trans);
152     
153     public String[] args() {
154         return env.get(ssargs);
155     }
156         
157     public boolean isDryRun()
158     {
159         return dryRun;
160     }
161     
162         public boolean isSpecial(String user) {
163                 if (specialNames != null && specialNames.contains(user)) {
164                         env.info().log("specialName: " + user);
165
166                         return (true);
167                 } else {
168                         return (false);
169                 }
170         }
171         
172         public boolean isMechID(String user) {
173                 if (user.matches("m[0-9][0-9][0-9][0-9][0-9]")) {
174                         return (true);
175                 } else {
176                         return (false);
177                 }
178         }
179
180         protected PrintStream fallout(PrintStream inFallout, String logType)
181                         throws IOException {
182                 PrintStream fallout = inFallout;
183                 if (fallout == null) {
184                         File dir = new File("logs");
185                         if (!dir.exists()) {
186                                 dir.mkdirs();
187                         }
188
189                         File f = null;
190                         long uniq = System.currentTimeMillis();
191
192                         f = new File(dir, getClass().getSimpleName() + "_" + logType + "_"
193                                         + uniq + ".log");
194
195                         fallout = new PrintStream(new FileOutputStream(f, true));
196                 }
197                 return fallout;
198         }
199
200         public Organization getOrgFromID(AuthzTrans trans, String user) {
201                 Organization organization;
202                 try {
203                         organization = OrganizationFactory.obtain(trans.env(),user.toLowerCase());
204                 } catch (OrganizationException e1) {
205                         trans.error().log(e1);
206                         organization=null;
207                 }
208
209                 if (organization == null) {
210                         PrintStream fallout = null;
211
212                         try {
213                                 fallout = fallout(fallout, "Fallout");
214                                 fallout.print("INVALID_ID,");
215                                 fallout.println(user);
216                         } catch (Exception e) {
217                                 env.error().log("Could not write to Fallout File", e);
218                         }
219                         return (null);
220                 }
221
222                 return (organization);
223         }
224         
225         public static Row executeDeleteQuery(Statement stmt) {
226                 Row row = null;
227                 if (!dryRun) {
228                         row = session.execute(stmt).one();
229                 }
230
231                 return (row);
232
233         }
234         
235         public static int acquireRunLock(String className) {
236                 Boolean testEnv = true;
237                 String envStr = env.getProperty("AFT_ENVIRONMENT");
238
239                 if (envStr != null) {
240                         if ("AFTPRD".equals(envStr)) {
241                                 testEnv = false;
242                         }
243                 } else {
244                         env.fatal()
245                                         .log("AFT_ENVIRONMENT property is required and was not found. Exiting.");
246                         System.exit(1);
247                 }
248
249                 if (testEnv) {
250                         env.info().log("TESTMODE: skipping RunLock");
251                         return (1);
252                 }
253
254                 String hostname = null;
255                 try {
256                         hostname = InetAddress.getLocalHost().getHostName();
257                 } catch (UnknownHostException e) {
258                         e.printStackTrace();
259                         env.warn().log("Unable to get hostname");
260                         return (0);
261                 }
262
263                 ResultSet existing = session.execute(String.format(
264                                 "select * from authz.run_lock where class = '%s'", className));
265
266                 for (Row row : existing) {
267                         long curr = System.currentTimeMillis();
268                         ByteBuffer lastRun = row.getBytesUnsafe(2); // Can I get this field
269                                                                                                                 // by name?
270
271                         long interval = (1 * 60 * 1000); // @@ Create a value in props file
272                                                                                                 // for this
273                         long prev = lastRun.getLong();
274
275                         if ((curr - prev) <= interval) {
276                                 env.warn().log(
277                                                 String.format("Too soon! Last run was %d minutes ago.",
278                                                                 ((curr - prev) / 1000) / 60));
279                                 env.warn().log(
280                                                 String.format("Min time between runs is %d minutes ",
281                                                                 (interval / 1000) / 60));
282                                 env.warn().log(
283                                                 String.format("Last ran on machine: %s at %s",
284                                                                 row.getString("host"), row.getDate("start")));
285                                 return (0);
286                         } else {
287                                 env.info().log("Delete old lock");
288                                 deleteLock(className);
289                         }
290                 }
291
292                 GregorianCalendar current = new GregorianCalendar();
293
294                 // We want our time in UTC, hence "+0000"
295                 SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss+0000");
296                 fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
297
298                 String cql = String
299                                 .format("INSERT INTO authz.run_lock (class,host,start) VALUES ('%s','%s','%s') IF NOT EXISTS",
300                                                 className, hostname, fmt.format(current.getTime()));
301
302                 env.info().log(cql);
303
304                 Row row = session.execute(cql).one();
305                 if (!row.getBool("[applied]")) {
306                         env.warn().log("Lightweight Transaction failed to write lock.");
307                         env.warn().log(
308                                         String.format("host with lock: %s, running at %s",
309                                                         row.getString("host"), row.getDate("start")));
310                         return (0);
311                 }
312                 return (1);
313         }
314         
315     private static void deleteLock( String className) {
316         Row row = session.execute( String.format( "DELETE FROM authz.run_lock WHERE class = '%s' IF EXISTS", className ) ).one();
317         if (! row.getBool("[applied]")) {
318             env.info().log( "delete failed" );
319         }
320     }
321
322     private static void transferVMProps(AuthzEnv env, String ... props) {
323                 String value;
324                 for(String key : props) {
325                         if((value = System.getProperty(key))!=null) {
326                             env.setProperty(key, value);
327                         }
328                 }
329         }
330         
331         // IMPORTANT! VALIDATE Organization isUser method
332     protected void checkOrganizationAcccess(AuthzTrans trans, Question q) throws APIException, OrganizationException {
333                         Set<String> testUsers = new HashSet<>();
334                         Result<List<RoleDAO.Data>> rrd = q.roleDAO.readNS(trans, rootNs);
335                         if (rrd.isOK()) {
336                                 for (RoleDAO.Data r : rrd.value) {
337                                         Result<List<UserRoleDAO.Data>> rur = q.userRoleDAO.readByRole(trans, r.fullName());
338                                         if (!rur.isOK()) {
339                                                 continue;
340                                         }
341                                         for (UserRoleDAO.Data udd : rur.value) {
342                                                 testUsers.add(udd.user);
343                                         }
344                                 }
345                                 if (testUsers.size() < 2) {
346                                         throw new APIException("Not enough Users in Roles for " + rootNs + " to Validate");
347                                 }
348
349                                 Identity iden;
350                                 for (String user : testUsers) {
351                                         if ((iden = org.getIdentity(trans, user)) == null) {
352                                                 throw new APIException("Failed Organization Entity Validation Check: " + user);
353                                         } else {
354                                                 trans.info().log("Organization Validation Check: " + iden.id());
355                                         }
356                                 }
357                         }
358                 }
359     
360     protected static String logDir() {
361         String ld = env.getProperty(LOG_DIR);
362         if(ld==null) {
363                 if(batchEnv==null) { // Deployed Batch doesn't use different ENVs, and a common logdir
364                                 ld = "logs/";
365                         } else {
366                                 ld = "logs/"+batchEnv;
367                         }
368         }
369         return ld;
370     }
371         protected int count(String str, char c) {
372                 if(str==null || str.isEmpty()) {
373                         return 0;
374                 } else {
375                         int count=1;
376                         for(int i=str.indexOf(c);i>=0;i=str.indexOf(c,i+1)) {
377                                 ++count;
378                         }
379                         return count;
380                 }
381         }
382
383         public final void close(AuthzTrans trans) {
384             _close(trans);
385             cluster.close();
386         }
387
388         public static void main(String[] args) {
389                 PropAccess access = new PropAccess(args);
390                 InputStream is = null;
391                 String filename;
392                 String propLoc;
393                 try {
394                         Define.set(access);
395                         rootNs =Define.ROOT_NS();
396                         
397                         File f = new File("etc/authzBatch.props");
398                         try {
399                                 if (f.exists()) {
400                                         filename = f.getAbsolutePath();
401                                         is = new FileInputStream(f);
402                                         propLoc = f.getPath();
403                                 } else {
404                                         URL rsrc = ClassLoader.getSystemResource("authBatch.props");
405                                         filename = rsrc.toString();
406                                         is = rsrc.openStream();
407                                         propLoc = rsrc.getPath();
408                                 }
409                                 access.load(is);
410                         } finally {
411                                 if (is == null) {
412                                         System.err.println("authBatch.props must exist in etc dir, or in Classpath");
413                                         System.exit(1);
414                                 }
415                                 is.close();
416                         }
417
418                         env = new AuthzEnv(access);
419
420                         transferVMProps(env, CASS_ENV, "DRY_RUN", "NS", "Organization");
421
422                         // Flow all Env Logs to Log4j, with ENV
423
424                         LogFileNamer lfn;
425                         lfn = new LogFileNamer(logDir(),"").noPID();
426                         lfn.setAppender("authz-batch");
427                         lfn.setAppender("aspr|ASPR");
428                         lfn.setAppender("sync");
429                         lfn.setAppender("jobchange");
430                         lfn.setAppender("validateuser");
431                         aspr = Logger.getLogger("aspr");
432                         Log4JLogTarget.setLog4JEnv("authz-batch", env);
433                         if (filename != null) {
434                                 env.init().log("Instantiated properties from", filename);
435                         }
436
437                         // Log where Config found
438                         env.info().log("Configuring from", propLoc);
439                         propLoc = null;
440
441                         Batch batch = null;
442                         // setup ATTUser and Organization Slots before starting this:
443                         // TODO redo this
444                         // env.slot(ATT.ATT_USERSLOT);
445                         //
446                         // OrganizationFactory.setDefaultOrg(env, ATT.class.getName());
447                         AuthzTrans trans = env.newTrans();
448
449                         TimeTaken tt = trans.start("Total Run", Env.SUB);
450                         try {
451                                 int len = args.length;
452                                 if (len > 0) {
453                                         String toolName = args[0];
454                                         len -= 1;
455                                         if (len < 0)
456                                                 len = 0;
457                                         String nargs[] = new String[len];
458                                         if (len > 0) {
459                                                 System.arraycopy(args, 1, nargs, 0, len);
460                                         }
461
462                                         env.put(ssargs = env.staticSlot("ARGS"), nargs);
463
464                                         /*
465                                          * Add New Batch Programs (inherit from Batch) here
466                                          */
467
468                                         // Might be a Report, Update or Temp Batch
469                                         Class<?> cls;
470                                         String classifier = "";
471                                         try {
472                                                 cls = ClassLoader.getSystemClassLoader().loadClass("org.onap.aaf.auth.update." + toolName);
473                                                 classifier = "Update:";
474                                         } catch (ClassNotFoundException e) {
475                                                 try {
476                                                         cls = ClassLoader.getSystemClassLoader().loadClass("org.onap.aaf.auth.reports." + toolName);
477                                                         classifier = "Report:";
478                                                 } catch (ClassNotFoundException e2) {
479                                                         try {
480                                                                 cls = ClassLoader.getSystemClassLoader()
481                                                                                 .loadClass("org.onap.aaf.auth.temp." + toolName);
482                                                                 classifier = "Temp Utility:";
483                                                         } catch (ClassNotFoundException e3) {
484                                                                 cls = null;
485                                                         }
486                                                 }
487                                         }
488                                         if (cls != null) {
489                                                 Constructor<?> cnst = cls.getConstructor(new Class[] { AuthzTrans.class });
490                                                 batch = (Batch) cnst.newInstance(trans);
491                                                 env.info().log("Begin", classifier, toolName);
492                                         }
493                                 
494
495                                         if (batch == null) {
496                                                 trans.error().log("No Batch named", toolName, "found");
497                                         }
498                                         /*
499                                          * End New Batch Programs (inherit from Batch) here
500                                          */
501
502                                 }
503                                 if (batch != null) {
504                                         batch.run(trans);
505                                 }
506                         } finally {
507                                 tt.done();
508                                 if (batch != null) {
509                                         batch.close(trans);
510                                 }
511                                 StringBuilder sb = new StringBuilder("Task Times\n");
512                                 trans.auditTrail(4, sb, AuthzTrans.SUB, AuthzTrans.REMOTE);
513                                 trans.info().log(sb);
514                         }
515                 } catch (Exception e) {
516                         e.printStackTrace(System.err);
517                         // Exceptions thrown by DB aren't stopping the whole process.
518                         System.exit(1);
519                 }
520         }
521
522 }
523