AT&T 2.0.19 Code drop, stage 3
[aaf/authz.git] / auth / auth-batch / src / main / java / org / onap / aaf / auth / update / Expiring.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.update;
23
24 import java.io.BufferedReader;
25 import java.io.File;
26 import java.io.FileOutputStream;
27 import java.io.FileReader;
28 import java.io.IOException;
29 import java.io.PrintStream;
30 import java.util.Date;
31 import java.util.GregorianCalendar;
32 import java.util.List;
33 import java.util.UUID;
34
35 import org.onap.aaf.auth.Batch;
36 import org.onap.aaf.auth.BatchPrincipal;
37 import org.onap.aaf.auth.actions.Action;
38 import org.onap.aaf.auth.actions.ActionDAO;
39 import org.onap.aaf.auth.actions.CacheTouch;
40 import org.onap.aaf.auth.actions.CredDelete;
41 import org.onap.aaf.auth.actions.CredPrint;
42 import org.onap.aaf.auth.actions.Email;
43 import org.onap.aaf.auth.actions.Message;
44 import org.onap.aaf.auth.actions.URDelete;
45 import org.onap.aaf.auth.actions.URFutureApprove;
46 import org.onap.aaf.auth.actions.URFutureApproveExec;
47 import org.onap.aaf.auth.actions.URPrint;
48 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
49 import org.onap.aaf.auth.dao.cass.CredDAO;
50 import org.onap.aaf.auth.dao.cass.FutureDAO;
51 import org.onap.aaf.auth.dao.hl.Function.FUTURE_OP;
52 import org.onap.aaf.auth.dao.hl.Function.OP_STATUS;
53 import org.onap.aaf.auth.env.AuthzTrans;
54 import org.onap.aaf.auth.helpers.Approval;
55 import org.onap.aaf.auth.helpers.Cred;
56 import org.onap.aaf.auth.helpers.Future;
57 import org.onap.aaf.auth.helpers.NS;
58 import org.onap.aaf.auth.helpers.Role;
59 import org.onap.aaf.auth.helpers.UserRole;
60 import org.onap.aaf.auth.helpers.Cred.Instance;
61 import org.onap.aaf.auth.layer.Result;
62 import org.onap.aaf.auth.org.OrganizationException;
63 import org.onap.aaf.auth.org.Organization.Identity;
64 import org.onap.aaf.misc.env.APIException;
65 import org.onap.aaf.misc.env.Env;
66 import org.onap.aaf.misc.env.TimeTaken;
67 import org.onap.aaf.misc.env.util.Chrono;
68
69 public class Expiring extends Batch {
70         private CredPrint crPrint;
71         private URFutureApprove urFutureApprove;
72         private URFutureApproveExec urFutureApproveExec;
73         private CredDelete crDelete;
74         private URDelete urDelete;
75         private final CacheTouch cacheTouch;
76         private final AuthzTrans noAvg;
77         private final ApprovalDAO apprDAO;
78         private final FutureDAO futureDAO;
79         private final PrintStream urDeleteF,urRecoverF;
80         private final URPrint urPrint;
81         private Email email;
82         private File deletesFile;
83
84         public Expiring(AuthzTrans trans) throws APIException, IOException, OrganizationException {
85                 super(trans.env());
86             trans.info().log("Starting Connection Process");
87             
88                 noAvg = env.newTransNoAvg();
89                 noAvg.setUser(new BatchPrincipal("batch:Expiring"));
90                 
91             TimeTaken tt0 = trans.start("Cassandra Initialization", Env.SUB);
92             try {
93                         crPrint = new CredPrint("Expired:");
94
95                         TimeTaken tt = trans.start("Connect to Cluster with DAOs", Env.REMOTE);
96                         try {
97                                 urFutureApprove = new URFutureApprove(trans, cluster,isDryRun());
98                                 checkOrganizationAcccess(trans, urFutureApprove.question());
99                                 urFutureApproveExec = new URFutureApproveExec(trans, urFutureApprove);
100                                 urPrint = new URPrint("User Roles:");
101                                 crDelete = new CredDelete(trans, urFutureApprove);
102                                 urDelete = new URDelete(trans,urFutureApprove);
103                                 cacheTouch = new CacheTouch(trans, urFutureApprove);
104                                 
105                                 // Reusing... don't destroy
106                                 apprDAO = urFutureApprove.question().approvalDAO;
107                                 futureDAO = urFutureApprove.question().futureDAO;
108
109                                 TimeTaken tt2 = trans.start("Connect to Cluster", Env.REMOTE);
110                                 try {
111                                         session = urFutureApprove.getSession(trans);
112                                 } finally {
113                                         tt2.done();
114                                 }
115                         } finally {
116                                 tt.done();
117                         }
118                         
119                         File data_dir = new File(env.getProperty("aaf_data_dir"));
120                         if(!data_dir.exists() || !data_dir.canWrite() || !data_dir.canRead()) {
121                                 throw new IOException("Cannot read/write to Data Directory "+ data_dir.getCanonicalPath() + ": EXITING!!!");
122                         }
123                         UserRole.setDeleteStream(
124                                 urDeleteF = new PrintStream(new FileOutputStream(deletesFile = new File(data_dir,"UserRoleDeletes.dat"),false)));
125                         UserRole.setRecoverStream(
126                                 urRecoverF = new PrintStream(new FileOutputStream(new File(data_dir,"UserRoleRecover.dat"),false)));
127                         UserRole.load(trans, session, UserRole.v2_0_11);
128                         
129                         Cred.load(trans, session);
130                         NS.load(trans, session,NS.v2_0_11);
131                         Future.load(trans,session,Future.withConstruct);
132                         Approval.load(trans,session,Approval.v2_0_17);
133                         Role.load(trans, session);
134                         
135                         email = new Email();
136                         email.subject("AAF Expiring Process Alert (ENV: %s)",batchEnv);
137                         email.preamble("Expiring Process Alert for %s",batchEnv);
138                         email.signature("Sincerely,\nAAF Expiring Batch Process\n");
139                         String address = env.getProperty("ALERT_TO_ADDRESS");
140                         if(address==null) {
141                                 throw new APIException("ALERT_TO_ADDRESS property is required");
142                         }
143                         email.addTo(address);
144         
145             } catch (OrganizationException e) {
146                 throw new APIException("Error getting valid Organization",e);
147                 } finally {
148                 tt0.done();
149             }
150         }
151
152         @Override
153         protected void run(AuthzTrans trans) {
154                 // Setup Date boundaries
155                 
156         final GregorianCalendar gc = new GregorianCalendar();
157         final Date now = gc.getTime();
158         
159         gc.add(GregorianCalendar.MONTH, 1);
160         Date future = gc.getTime();
161 //          Date earliest = null;
162
163         // reset
164         gc.setTime(now);
165         gc.add(GregorianCalendar.DAY_OF_MONTH, -7); // save Expired Roles for 7 days.
166         Date tooLate = gc.getTime();
167         
168         TimeTaken tt;
169        
170         // Clean out Approvals UserRoles are fixed up.
171                 String memo;
172                 for(List<Approval> la : Approval.byUser.values()) {
173                         for(Approval a : la ) {
174                                 memo = a.getMemo();
175                                 if(memo!=null && (memo.contains("Re-Approval") || memo.contains("Re-Validate"))) {
176                                         String role = a.getRole();
177                                         if(role!=null) {
178                                                 UserRole ur = UserRole.get(a.getUser(), a.getRole());
179                                                 Future f=null;
180                                                 if(ur!=null) {
181                                                         if(ur.expires().after(future)) { // no need for Approval anymore
182                                                                 a.delayDelete(noAvg, apprDAO, dryRun, "User Role already Extended");
183                                                                 UUID tkt = a.getTicket();
184                                                                 if(tkt!=null) {
185                                                                         f = Future.data.get(tkt);
186                                                                 }
187                                                         }
188                                                 } else {
189                                                         a.delayDelete(noAvg, apprDAO, dryRun, "User Role does not exist");
190                                                         f = Future.data.get(a.getTicket());
191                                                 }
192                                                 if(f!=null) {
193                                                         f.delayedDelete(noAvg, futureDAO, dryRun, "Approvals removed");
194                                                 }
195                                         }
196                                 }
197                         }
198                 }
199                 try {
200                         trans.info().log("### Removed",Future.sizeForDeletion(),"Future and",Approval.sizeForDeletion(),"Approvals");
201                         Future.resetLocalData();
202                 Approval.resetLocalData();
203                 } catch (Throwable t) {
204                         t.printStackTrace();
205                 }
206         
207         // Run for Expired Futures
208         trans.info().log("Checking for Expired Approval/Futures");
209         tt = trans.start("Delete old Futures", Env.REMOTE);
210                 trans.info().log("### Running Future Execution on ",Future.data.size(), "Items");
211                 // Execute any Futures waiting
212                 for(Future f : Future.data.values()) {
213                         if(f.memo().contains("Re-Approval") || f.memo().contains("Re-Validate")) {
214                                 List<Approval> la = Approval.byTicket.get(f.id());
215                                 if(la!=null) {
216                                         Result<OP_STATUS> ruf = urFutureApproveExec.exec(noAvg,la,f);
217                                         if(ruf.isOK()) {
218                                                 switch(ruf.value) {
219                                                         case P:
220                                                                 break;
221                                                         case E:
222                                                         case D:
223                                                         case L:
224                                                                 f.delayedDelete(noAvg, futureDAO, dryRun,OP_STATUS.L.desc());
225                                                                 Approval.delayDelete(noAvg, apprDAO, dryRun, la,OP_STATUS.L.desc());
226                                                                 break;
227                                                 }
228                                         }
229                                 }
230                         }
231                 }
232                 try {
233                         trans.info().log("### Removed",Future.sizeForDeletion(),"Future and",Approval.sizeForDeletion(),"Approvals");
234                         Future.resetLocalData();
235                 Approval.resetLocalData();
236                 } catch (Throwable t) {
237                         t.printStackTrace();
238                 }
239
240         
241                 trans.info().log("### Remove Expired on ",Future.data.size(), "Items, or premature ones");
242         // Remove Expired
243                 String expiredBeforeNow = "Expired before " + tooLate;
244                 String expiredAfterFuture = "Expired after " + future;
245         try {
246                         for(Future f : Future.data.values()) {
247                                 if(f.expires().before(tooLate)) {
248                                         f.delayedDelete(noAvg,futureDAO,dryRun, expiredBeforeNow);
249                                         Approval.delayDelete(noAvg, apprDAO, dryRun, Approval.byTicket.get(f.id()), expiredBeforeNow);
250                                 } else if(f.expires().after(future)) {
251                                         f.delayedDelete(noAvg,futureDAO,dryRun, expiredAfterFuture);
252                                         Approval.delayDelete(noAvg,apprDAO,dryRun, Approval.byTicket.get(f.id()), expiredAfterFuture);
253                                 }
254                         }
255                         try {
256                                 trans.info().log("### Removed",Future.sizeForDeletion(),"Future and",Approval.sizeForDeletion(),"Approvals");
257                                 Future.resetLocalData();
258                     Approval.resetLocalData();
259                         } catch (Throwable t) {
260                                 t.printStackTrace();
261                         }
262         } finally {
263                         tt.done();      
264         }
265         
266                 trans.info().log("### Checking Approvals valid (",Approval.byApprover.size(),"Items)");
267         // Make sure users of Approvals are still valid
268         for(List<Approval> lapp : Approval.byTicket.values()) {
269                         for(Approval app : lapp) {
270                                 Future f;
271                                 if(app.getTicket()==null) {
272                                         f = null;
273                                 } else {
274                                         f = Future.data.get(app.getTicket());
275                                         if(Future.pendingDelete(f)) {
276                                                 f=null;
277                                         }
278                                 }
279                                 String msg;
280                                 if(f!=null && app.getRole()!=null && Role.byName.get(app.getRole())==null) {
281                                         f.delayedDelete(noAvg,futureDAO,dryRun,msg="Role '" + app.getRole() + "' no longer exists");
282                                         Approval.delayDelete(noAvg,apprDAO,dryRun, Approval.byTicket.get(f.id()), msg);
283                                                 continue;
284                                 }
285                                 
286                                 switch(app.getStatus()) {
287                                         case "pending":
288                                                 if(f==null) {
289                                                         app.delayDelete(noAvg,apprDAO, isDryRun(), "ticketDeleted");
290                                                         continue;
291                                                 }
292                                                 switch(app.getType()) {
293                                                         case "owner":
294                                                                 boolean anOwner=false;
295                                                                 String approle = app.getRole();
296                                                                 if(approle!=null) {
297                                                                         Role role = Role.byName.get(approle);
298                                                                         if(role==null) {
299                                                                                 app.delayDelete(noAvg, apprDAO, dryRun, "Role No Longer Exists");
300                                                                                 continue;
301                                                                         } else {
302                                                                         // Make sure Owner Role exists
303                                                                                 String owner = role.ns + ".owner";
304                                                                                 if(Role.byName.containsKey(owner)) {
305                                                                                         List<UserRole> lur = UserRole.byRole.get(owner);
306                                                                                         if(lur != null) {
307                                                                                                 for(UserRole ur : lur) {
308                                                                                                         if(ur.user().equals(app.getApprover())) {
309                                                                                                                 anOwner = true;
310                                                                                                                 break;
311                                                                                                         }
312                                                                                                 }
313                                                                                         }
314                                                                                 }
315                                                                         }
316                                                                         if(!anOwner) {
317                                                                                 app.delayDelete(noAvg, apprDAO, dryRun, "No longer Owner");
318                                                                         }
319         
320                                                                 }
321                                                                 break;
322                                                         case "supervisor":
323                                                                 try {
324                                                                         Identity identity = org.getIdentity(noAvg, app.getUser());
325                                                                         if(identity==null) {
326                                                                                 if(f!=null) {
327                                                                                         f.delayedDelete(noAvg,futureDAO,dryRun,msg = app.getUser() + " is no longer associated with " + org.getName());
328                                                                                         Approval.delayDelete(noAvg,apprDAO,dryRun, Approval.byTicket.get(f.id()), msg);
329                                                                                 }
330                                                                         } else {
331                                                                                 if(!app.getApprover().equals(identity.responsibleTo().fullID())) {
332                                                                                         if(f!=null) {
333                                                                                                 f.delayedDelete(noAvg,futureDAO,dryRun,msg = app.getApprover() + " is no longer a Supervisor of " + app.getUser());
334                                                                                                 Approval.delayDelete(noAvg,apprDAO,dryRun, Approval.byTicket.get(f.id()), msg);
335                                                                                         }
336                                                                                 }
337                                                                         }
338                                                                 } catch (OrganizationException e) {
339                                                                         e.printStackTrace();
340                                                                 }
341                                                         break;
342                                                 }
343                                                 break;
344                                 }
345                         }
346         }
347                 try {
348                         trans.info().log("### Removed",Future.sizeForDeletion(),"Future and",Approval.sizeForDeletion(),"Approvals");
349                         Future.resetLocalData();
350                 Approval.resetLocalData();
351                 } catch (Throwable t) {
352                         t.printStackTrace();
353                 }
354         
355         int count = 0, deleted=0, delayedURDeletes = 0;
356
357         // Run for User Roles
358         trans.info().log("Checking for Expired User Roles");
359         try {
360                         for(UserRole ur : UserRole.data) {
361                                 if(org.getIdentity(noAvg, ur.user())==null) {  // if not part of Organization;
362                                         if(isSpecial(ur.user())) {
363                                                 trans.info().log(ur.user(),"is not part of organization, but may not be deleted");
364                                         } else {
365                                                 ur.delayDelete(noAvg, "Not Part of Organization", dryRun);
366                                                 ++deleted;
367                                                 ++delayedURDeletes;
368                                         }
369                                 } else {
370                                         if(NS.data.get(ur.ns())==null) {
371                                         ur.delayDelete(noAvg,"Namespace " + ur.ns() + " does not exist.",dryRun);
372                                         ++delayedURDeletes;
373                                         ++deleted;
374                                         } else if(!Role.byName.containsKey(ur.role())) {
375                                                 ur.delayDelete(noAvg,"Role " + ur.role() + " does not exist.",dryRun);
376                                         ++deleted;
377                                         ++delayedURDeletes;
378                                         } else if(ur.expires().before(tooLate)) {
379                                                 if("owner".equals(ur.rname())) { // don't delete Owners, even if Expired
380                                                         urPrint.exec(noAvg,ur,"Owner Expired (but not deleted)");
381                                                 } else {
382                                                         // In this case, when UR is expired, not dependent on other lookups, we delete straight out.
383                                                         urDelete.exec(noAvg, ur,"Expired before " + tooLate);
384                                                         ++deleted;
385                                                 }
386                                         //trans.logAuditTrail(trans.info());
387                                         } else if(ur.expires().before(future) && ur.expires().after(now)) {
388                                                 ++count;
389                                                 // Is there an Approval set already
390                                                 boolean needNew = true;
391                                                 if(ur.role()!=null && ur.user()!=null) {
392                                                         List<Approval> abm = Approval.byUser.get(ur.user());
393                                                         if(abm!=null) {
394                                                                 for(Approval a : abm) {
395                                                                         if(a.getOperation().equals(FUTURE_OP.A.name()) && ur.role().equals(a.getRole())) {
396                                                                                 if(Future.data.get(a.getTicket())!=null) {
397                                                                                         needNew = false;
398                                                                                         break;
399                                                                                 }
400                                                                         }
401                                                                 }
402                                                         }
403                                                 }
404                                                 if(needNew) {
405                                                         urFutureApprove.exec(noAvg, ur,"");
406                                                 }
407                                         }
408                                 }
409                         }
410                 } catch (OrganizationException e) {
411                         env.info().log(e,"Exiting ...");
412                 } finally {
413                         env.info().log("Found",count,"user roles expiring before",future);
414                         env.info().log("deleting",deleted,"user roles expiring before",tooLate);
415         }
416         
417         // Actualize UR Deletes, or send Email
418         if(UserRole.sizeForDeletion()>0) {
419                         count+=UserRole.sizeForDeletion();
420             double onePercent = 0.01;
421                 if(((double)UserRole.sizeForDeletion())/UserRole.data.size() > onePercent) {
422                                 Message msg = new Message();
423                                 try {
424                                         msg.line("Found %d of %d UserRoles marked for Deletion in file %s", 
425                                                 delayedURDeletes,UserRole.data.size(),deletesFile.getCanonicalPath());
426                                 } catch (IOException e) {
427                                         msg.line("Found %d of %d UserRoles marked for Deletion.\n", 
428                                                         delayedURDeletes);
429                                 }
430                                 msg.line("Review the File.  If data is ok, Use ExpiringP2 BatchProcess to complete the deletions");
431                                 
432                                 email.msg(msg);
433                                 email.exec(trans, org, "Email Support");
434                 } else {
435                                 urDeleteF.flush();
436                                 try {
437                                         BufferedReader br = new BufferedReader(new FileReader(deletesFile));
438                                         try {
439                                                 ExpiringP2.deleteURs(noAvg, br, urDelete, null /* don't touch Cache here*/);
440                                         } finally {
441                                                 br.close();
442                                         }
443                                 } catch (IOException io) {
444                                         noAvg.error().log(io);
445                                 }
446                 }
447         }
448         if(count>0) {
449                         String str = String.format("%d UserRoles modified or deleted", count);
450                         cacheTouch.exec(trans, "user_role", str);
451         }
452         
453         // Run for Creds
454         trans.info().log("Checking for Expired Credentials");
455         System.out.flush();
456         count = 0;
457         try {
458                         CredDAO.Data crd = new CredDAO.Data();
459                         Date last = null;
460                         for( Cred creds : Cred.data.values()) {
461                                 crd.id = creds.id;
462                                 for(int type : creds.types()) {
463                                         crd.type = type;
464                                         for( Instance inst : creds.instances) {
465                                                 if(inst.expires.before(tooLate)) {
466                                                         crd.expires = inst.expires;
467                                                         crDelete.exec(noAvg, crd,"Expired before " + tooLate);
468                                                 } else if(last==null || inst.expires.after(last)) {
469                                                         last = inst.expires;
470                                                 }
471                                         }
472                                         if(last!=null) {
473                                                 if(last.before(future)) {
474                                                         crd.expires = last;
475                                                         crPrint.exec(noAvg, crd,"");
476                                                         ++count;
477                                                 }
478                                         }
479                                 }
480                         }
481         } finally {
482                         String str = String.format("Found %d current creds expiring before %s", count, Chrono.dateOnlyStamp(future));
483                         if(count>0) {
484                                 cacheTouch.exec(trans, "cred", str);
485                         }
486         }
487         
488         }
489         
490         @Override
491         protected void _close(AuthzTrans trans) {
492         aspr.info("End " + this.getClass().getSimpleName() + " processing" );
493         for(Action<?,?,?> action : new Action<?,?,?>[] {crDelete}) {
494                 if(action instanceof ActionDAO) {
495                         ((ActionDAO<?,?,?>)action).close(trans);
496                 }
497         }
498         session.close();
499         urDeleteF.close();
500         urRecoverF.close();
501         }
502
503 }