Upgrade to latest oparent
[aaf/authz.git] / authz-batch / src / main / java / com / att / authz / JobChange.java
1 /*******************************************************************************
2  * Copyright (c) 2016 AT&T Intellectual Property. All rights reserved.
3  *******************************************************************************/
4 // test for case where I'm an admin
5
6 package com.att.authz;
7
8 import java.io.BufferedInputStream;
9 import java.io.BufferedReader;
10 import java.io.BufferedWriter;
11 import java.io.File;
12 import java.io.FileInputStream;
13 import java.io.FileWriter;
14 import java.io.IOException;
15 import java.io.InputStreamReader;
16 import java.io.PrintStream;
17 import java.net.MalformedURLException;
18 import java.net.URL;
19 import java.text.SimpleDateFormat;
20 import java.util.ArrayList;
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.Map;
25 import java.util.Set;
26
27 import com.att.authz.env.AuthzTrans;
28 import com.att.authz.org.Organization;
29 import com.att.authz.org.OrganizationFactory;
30 import org.onap.aaf.inno.env.APIException;
31 import com.datastax.driver.core.ResultSet;
32 import com.datastax.driver.core.Row;
33 import com.datastax.driver.core.SimpleStatement;
34 import com.datastax.driver.core.Statement;
35
36 public class JobChange extends Batch
37 {
38     private class UserRole
39     {
40         String user;
41         String role;
42     }
43     private class UserCred
44     {
45         String user;
46         String ns;
47     }
48     
49     private class NamespaceOwner
50     {
51         String user;
52         String ns;
53         boolean responsible;
54         int ownerCount;
55     }
56     
57
58     private AuthzTrans myTrans;
59
60         private Map<String, ArrayList<UserRole>> rolesMap = new HashMap<String, ArrayList<UserRole>>();
61         private Map<String, ArrayList<NamespaceOwner>> ownersMap = new HashMap<String, ArrayList<NamespaceOwner>>();
62     private Map<String, ArrayList<UserCred>> credsMap = new HashMap<String, ArrayList<UserCred>>();
63     
64     
65     public static void createDirectory( String dir )
66     {
67         File f = new File( dir );
68
69         if ( ! f.exists())
70         {
71             env.info().log( "creating directory: " + dir );
72             boolean result = false;
73
74             try
75             {
76                 f.mkdir();
77                 result = true;
78             } catch(SecurityException e){
79                 e.printStackTrace();
80             }        
81             if(result) {    
82                 System.out.println("DIR created");  
83             }
84         }        
85     }
86     
87     public static String getJobChangeDataFile()
88     {
89         File outFile = null;
90         BufferedWriter writer = null;
91         BufferedReader reader = null;
92         String line;
93         boolean errorFlag = false;
94
95         try
96         {
97             createDirectory( "etc" );
98             
99             outFile = new File("etc/jobchange." + getCurrentDate() );
100             if (!outFile.exists())
101             {
102                 outFile.createNewFile();
103             }
104             else
105             {
106                 return( "etc/jobchange." + getCurrentDate() );
107             }
108                         
109             env.info().log("Creating the local file with the webphone data");
110
111
112
113             writer = new BufferedWriter(new FileWriter(
114                                             outFile.getAbsoluteFile()));
115
116             URL u = new URL(  "ftp://thprod37.sbc.com/jobchange_Delta.dat" );
117             reader = new BufferedReader(new InputStreamReader(
118                                             new BufferedInputStream(u.openStream())));
119             while ((line = reader.readLine()) != null) {
120                 writer.write(line + "\n");
121             }
122                         
123             writer.close();
124             reader.close();
125             
126             env.info().log("Finished fetching the data from the webphone ftp site.");
127             return( "etc/jobchange." + getCurrentDate() );
128             
129         } catch (MalformedURLException e) {
130             env.error().log("Could not open the remote job change data file.", e);
131             errorFlag = true;
132
133         } catch (IOException e) {
134             env.error().log(
135                 "Error while opening or writing to the local data file.", e);
136             errorFlag = true;
137
138         } catch (Exception e) {
139             env.error().log("Error while fetching the data file.", e);
140             errorFlag = true;
141
142         } finally {
143             if (errorFlag)
144                 outFile.delete();
145         }
146                 return null;
147     }
148
149     public static String getCurrentDate()
150     {
151         SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
152         Date now = new Date();
153         String strDate = sdfDate.format(now);
154         return strDate;
155     }
156
157     public void loadUsersFromCred()
158     {
159         String query = "select id,ns from authz.cred" ;
160                                       
161         env.info().log( "query: " + query );
162
163         Statement stmt = new SimpleStatement( query );
164         ResultSet results = session.execute(stmt);
165
166         Iterator<Row> iter = results.iterator();
167         while( iter.hasNext() )
168         {
169             Row row = iter.next();
170             String user = row.getString( "id" );
171             String ns = row.getString( "ns" );
172             String simpleUser = user.substring( 0, user.indexOf( "@" ) );
173
174             if ( isMechID( simpleUser ) )
175             {
176                 continue;
177             }
178             else if ( credsMap.get( simpleUser ) == null )
179             {
180                 credsMap.put( simpleUser, new ArrayList<UserCred>() );
181                 
182                 UserCred newEntry = new UserCred();
183                 newEntry.user = user;
184                 newEntry.ns = ns;
185             
186                 credsMap.get( simpleUser ).add( newEntry );
187             }
188             else 
189             {
190                 UserCred newEntry = new UserCred();
191                 newEntry.user = user;
192                 newEntry.ns = ns;
193             
194                 credsMap.get( simpleUser ).add( newEntry );
195             }
196                 
197             env.debug().log( String.format( "\tUser: %s NS: %s", user, ns ) );
198         }
199     }
200
201     public void loadUsersFromRoles()
202     {
203         String query = "select user,role from authz.user_role" ;
204                                       
205         env.info().log( "query: " + query );
206
207         Statement stmt = new SimpleStatement( query );
208         ResultSet results = session.execute(stmt);
209         int total=0, flagged=0;
210
211         Iterator<Row> iter = results.iterator();
212         while( iter.hasNext() )
213         {
214             Row row = iter.next();
215             String user = row.getString( "user" );
216             String role = row.getString( "role" );
217             String simpleUser = user.substring( 0, user.indexOf( "@" ) );
218
219             if ( isMechID( simpleUser ) )
220             {
221                 continue;
222             }
223             else if ( rolesMap.get( simpleUser ) == null )
224             {
225                 rolesMap.put( simpleUser, new ArrayList<UserRole>() );
226                 
227                 UserRole newEntry = new UserRole();
228                 newEntry.user = user;
229                 newEntry.role = role;
230             
231                 rolesMap.get( simpleUser ).add( newEntry );
232             }
233             else
234             {
235                 UserRole newEntry = new UserRole();
236                 newEntry.user = user;
237                 newEntry.role = role;
238             
239                 rolesMap.get( simpleUser ).add( newEntry );
240             }
241                 
242             env.debug().log( String.format( "\tUser: %s Role: %s", user, role ) );
243
244             ++total;
245         }
246         env.info().log( String.format( "rows read: %d expiring: %d", total, flagged ) );
247     }
248
249     public void loadOwnersFromNS()
250     {
251         String query = "select name,admin,responsible from authz.ns" ;
252                                       
253         env.info().log( "query: " + query );
254
255         Statement stmt = new SimpleStatement( query );
256         ResultSet results = session.execute(stmt);
257
258         Iterator<Row> iter = results.iterator();
259         while( iter.hasNext() )
260         {
261             Row row = iter.next();
262             Set<String> responsibles = row.getSet( "responsible", String.class );
263
264             for ( String user : responsibles )
265             {
266                 env.info().log( String.format( "Found responsible %s", user ) );
267                 String simpleUser = user.substring( 0, user.indexOf( "@" ) );
268
269                 if ( isMechID( simpleUser ) )
270                 {
271                     continue;
272                 }
273                 else if ( ownersMap.get( simpleUser ) == null )
274                 {
275                     ownersMap.put( simpleUser, new ArrayList<NamespaceOwner>() );
276
277                     NamespaceOwner newEntry = new NamespaceOwner();
278                     newEntry.user = user;
279                     newEntry.ns   = row.getString( "name" );
280                     newEntry.ownerCount = responsibles.size();
281                     newEntry.responsible = true;
282                     ownersMap.get( simpleUser ).add( newEntry );
283                 }
284                 else 
285                 {
286                     NamespaceOwner newEntry = new NamespaceOwner();
287                     newEntry.user = user;
288                     newEntry.ns = row.getString( "name" );
289                     newEntry.ownerCount = responsibles.size();
290                     newEntry.responsible = true;                    
291                     ownersMap.get( simpleUser ).add( newEntry );
292                 }
293             }                
294             Set<String> admins = row.getSet( "admin", String.class );
295
296             for ( String user : admins )
297             {
298                 env.info().log( String.format( "Found admin %s", user ) );
299                 String simpleUser = user.substring( 0, user.indexOf( "@" ) );
300
301                 if ( isMechID( simpleUser ) )
302                 {
303                     continue;
304                 }
305                 else if ( ownersMap.get( simpleUser ) == null )
306                 {
307                     ownersMap.put( simpleUser, new ArrayList<NamespaceOwner>() );
308
309                     NamespaceOwner newEntry = new NamespaceOwner();
310                     newEntry.user = user;
311                     newEntry.ns   = row.getString( "name" );
312                     newEntry.responsible = false;
313                     newEntry.ownerCount = -1; //                     
314                     ownersMap.get( simpleUser ).add( newEntry );
315                 }
316                 else 
317                 {
318                     NamespaceOwner newEntry = new NamespaceOwner();
319                     newEntry.user = user;
320                     newEntry.ns = row.getString( "name" );
321                     newEntry.responsible = false;
322                     newEntry.ownerCount = -1; //                                         
323                     ownersMap.get( simpleUser ).add( newEntry );
324                 }
325             }                
326
327         }
328     }
329
330         /**
331          * Processes the specified JobChange data file obtained from Webphone. Each line is 
332          * read and processed and any fallout is written to the specified fallout file. 
333          * If fallout file already exists it is deleted and a new one is created. A
334          * comparison of the supervisor id in the job data file is done against the one returned 
335          * by the authz service and if the supervisor Id has changed then the record is updated
336          * using the authz service. An email is sent to the new supervisor to approve the roles 
337          * assigned to the user.
338          * 
339          * @param fileName - name of the file to process including its path
340          * @param falloutFileName - the file where the fallout entries have to be written
341          * @param validDate - the valid effective date when the user had moved to the new supervisor
342          * @throws Exception
343          */
344         public void processJobChangeDataFile(String fileName,
345                                          String falloutFileName, Date validDate) throws Exception
346     {
347         
348                 BufferedWriter writer = null;
349
350                 try {
351
352             env.info().log("Reading file: " + fileName );
353
354             FileInputStream fstream = new FileInputStream(fileName);
355             BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
356
357             String strLine;
358
359             while ((strLine = br.readLine()) != null)   {
360                 processLine( strLine, writer );
361             }
362
363             br.close();
364                         
365                         
366                 } catch (IOException e) {
367             env.error().log( "Error while reading from the input data file: " + e );
368                         throw e;
369         }
370     }
371
372     public void handleAdminChange( String user )
373     {
374         ArrayList<NamespaceOwner> val = ownersMap.get( user );
375         
376         for ( NamespaceOwner r : val )
377         {
378             env.info().log( "handleAdminChange: " + user );
379             AuthzTrans trans = env.newTransNoAvg();
380
381             
382             if ( r.responsible )
383             {
384                 env.info().log( String.format( "delete from NS owner: %s, NS: %s, count: %s",
385                                            r.user, r.ns, r.ownerCount ) );
386
387                 aspr.info( String.format( "action=DELETE_NS_OWNER, user=%s, ns=%s",
388                                       r.user, r.ns ) );
389                 if ( r.ownerCount < 2 )
390                 {
391                     // send warning email to aaf-support, after this deletion, no owner for NS
392                     ArrayList<String> toAddress = new ArrayList<String>();
393                     toAddress.add( "XXX_EMAIL" );
394                 
395                     env.warn().log( "removing last owner from namespace" );
396
397                     Organization org = null;
398                     org = getOrgFromID( myTrans, org, toAddress.get(0) );
399
400                     env.info().log( "calling getOrgFromID with " + toAddress.get(0) );
401
402                     if ( org != null )
403                     {
404                         try
405                         {
406                             aspr.info( String.format( "action=EMAIL_NO_OWNER_NS to=%s, user=%s, ns=%s",
407                                                       toAddress.get(0), r.user, r.ns ) );
408                             org.sendEmail( trans, toAddress,
409                                            new ArrayList<String>(),
410                                            String.format( "WARNING: no owners for AAF namespace '%s'", r.ns ), // subject:
411                                            String.format( "AAF recieved a jobchange notification for user %s who was the owner of the '%s' namespace. Please identify a new owner for this namespace and update AAF.", r.user, r.ns ), // body of msg
412                                            true );
413                         } catch (Exception e) {
414                             env.error().log("calling sendEmail()");
415                         
416                             e.printStackTrace();
417                         }
418                     }
419                     else
420                     {
421                         env.error().log( "Failed getOrgFromID" );
422                     }
423                 }
424             }
425             else
426             {
427                 env.info().log( String.format( "delete from NS admin: %s, NS: %s",
428                                            r.user, r.ns ) );
429
430                 aspr.info( String.format( "action=DELETE_NS_ADMIN, user=%s, ns=%s",
431                                           r.user, r.ns ) );
432             }                    
433             
434             String field = (r.responsible == true) ? "responsible" : "admin";
435             
436             String query = String.format( "update authz.ns set %s = %s - {'%s'} where name = '%s'",
437                                           field, field, r.user, r.ns ) ;                                   
438             env.info().log( "query: " + query );
439             Statement stmt = new SimpleStatement( query );
440             /*Row row = */session.execute(stmt).one();
441             
442             String attribQuery = String.format( "delete from authz.ns_attrib where ns = '%s' AND type='%s' AND name='%s'",
443                                 r.ns, field, r.user);
444             env.info().log( "ns_attrib query: " + attribQuery);
445             Statement attribStmt = new SimpleStatement( attribQuery );
446             /*Row attribRow = */session.execute(attribStmt).one();
447             
448         }
449     }
450
451     public void handleRoleChange( String user )
452     {
453         ArrayList<UserRole> val = rolesMap.get( user );
454         
455         for ( UserRole r : val )
456         {
457             env.info().log( "handleRoleChange: " + user );
458
459             env.info().log( String.format( "delete from %s from user_role: %s",
460                                            r.user, r.role ) );
461
462             aspr.info( String.format( "action=DELETE_FROM_ROLE, user=%s, role=%s",
463                                       r.user, r.role ) );
464
465
466             String query = String.format( "delete from authz.user_role where user = '%s' and role = '%s'",
467                                           r.user, r.role );
468                                       
469             env.info().log( "query: " + query );
470
471             Statement stmt = new SimpleStatement( query );
472             /* Row row = */ session.execute(stmt).one();
473
474         }
475     }
476     
477     public void handleCredChange( String user )
478     {
479         ArrayList<UserCred> val = credsMap.get( user );
480         
481         for ( UserCred r : val )
482         {
483             env.info().log( "handleCredChange: " + user );
484
485             env.info().log( String.format( "delete user %s cred from ns: %s",
486                                            r.user, r.ns ) );
487
488             aspr.info( String.format( "action=DELETE_FROM_CRED, user=%s, ns=%s",
489                                       r.user, r.ns ) );
490
491             String query = String.format( "delete from authz.cred where id = '%s'",
492                                           r.user );
493                                       
494             env.info().log( "query: " + query );
495
496             Statement stmt = new SimpleStatement( query );
497             /*Row row = */session.execute(stmt).one();
498
499         }
500
501     }
502     
503     public boolean processLine(String line, BufferedWriter writer) throws IOException
504     {
505         SimpleDateFormat sdfDate = new SimpleDateFormat("yyyyMMdd");
506         boolean errorFlag = false;
507         String errorMsg = "";
508
509         try
510         {
511             String[] phoneInfo = line.split( "\\|" );
512
513             if ((phoneInfo != null) && (phoneInfo.length >= 8)
514                 && (!phoneInfo[0].startsWith("#")))
515             {
516                 String user = phoneInfo[0];
517                 String newSupervisor = phoneInfo[7];
518                 Date effectiveDate = sdfDate.parse(phoneInfo[8].trim());
519
520                 env.debug().log( String.format( "checking user: %s, newSupervisor: %s, date: %s",
521                                                 user, newSupervisor, effectiveDate ) );
522                     
523                 // Most important case, user is owner of a namespace
524                 //
525                 if ( ownersMap.get( user ) != null )
526                 {
527                     env.info().log( String.format( "Found %s as a namespace admin/owner", user ) );
528                     handleAdminChange( user );
529                 }
530
531                 if ( credsMap.get( user ) != null )
532                 {
533                     env.info().log( String.format( "Found %s in cred table", user ) );
534                     handleCredChange( user );
535                 }
536
537                 if ( rolesMap.get( user ) != null )
538                 {
539                     env.info().log( String.format( "Found %s in a role ", user ) );
540                     handleRoleChange( user );
541                 }
542             }
543                 
544             else if (phoneInfo[0].startsWith("#"))
545             {
546                 return true;
547             }
548             else
549             {
550                 env.warn().log("Can't parse. Skipping the line." + line);
551                 errorFlag = true;
552             }
553         } catch (Exception e) {
554             errorFlag = true;
555             errorMsg = e.getMessage();
556             env.error().log( "Error while processing line:" + line +  e );
557             e.printStackTrace();
558         } finally {
559             if (errorFlag) {
560                 env.info().log( "Fallout enrty being written for line:" + line );
561                 writer.write(line + "|Failed to update supervisor for user:" + errorMsg + "\n");
562             }
563         }
564         return true;
565     }
566
567
568         public JobChange(AuthzTrans trans) throws APIException, IOException {
569                 super( trans.env() );
570         myTrans = trans;
571                 session = cluster.connect();
572         }
573
574     public Organization getOrgFromID( AuthzTrans trans, Organization _org, String user ) {
575         Organization org = _org;
576         if ( org == null || ! user.endsWith( org.getRealm() ) ) {
577             int idx = user.lastIndexOf('.');
578             if ( idx > 0 )
579                 idx = user.lastIndexOf( '.', idx-1 );
580
581             org = null;
582             if ( idx > 0 ) {
583                 try {
584                     org = OrganizationFactory.obtain( trans.env(), user.substring( idx+1 ) );
585                 } catch (Exception e) {
586                     trans.error().log(e,"Failure Obtaining Organization");
587                 }
588             }
589
590             if ( org == null ) {
591                 PrintStream fallout = null;
592
593                 try {
594                     fallout= fallout(fallout, "Fallout");
595                     fallout.print("INVALID_ID,");
596                     fallout.println(user);
597                 } catch (Exception e) {
598                     env.error().log("Could not write to Fallout File",e);
599                 } 
600                 return( null );
601             }
602         }
603         return( org );
604     }        
605
606     public void dumpOwnersMap()
607     {
608         for ( Map.Entry<String, ArrayList<NamespaceOwner>> e : ownersMap.entrySet() )
609         {
610             String key = e.getKey();
611             ArrayList<NamespaceOwner> values = e.getValue();
612
613             env.info().log( "ns user: " + key );
614
615             for ( NamespaceOwner r : values )
616             {
617                 env.info().log( String.format( "\tNS-user: %s, NS-name: %s, ownerCount: %d",
618                                                r.user, r.ns, r.ownerCount ) );
619
620             }
621         }
622     }
623
624     public void dumpRolesMap()
625     {
626         for ( Map.Entry<String, ArrayList<UserRole>> e : rolesMap.entrySet() )
627         {
628             String key = e.getKey();
629             ArrayList<UserRole> values = e.getValue();
630
631             env.info().log( "user: " + key );
632
633             for ( UserRole r : values )
634             {
635                 env.info().log( String.format( "\trole-user: %s, role-name: %s",
636                                                 r.user, r.role ) );
637             }
638         }
639     }
640     public void dumpCredMap()
641     {
642         for ( Map.Entry<String, ArrayList<UserCred>> e : credsMap.entrySet() )
643         {
644             String key = e.getKey();
645             ArrayList<UserCred> values = e.getValue();
646
647             env.info().log( "user: " + key );
648
649             for ( UserCred r : values )
650             {
651                 env.info().log( String.format( "\tcred-user: %s, ns: %s",
652                                                 r.user, r.ns ) );
653             }
654
655         }
656     }
657
658         @Override
659         protected void run (AuthzTrans trans)
660         {
661         if ( acquireRunLock( this.getClass().getName() ) != 1 ) {
662                 env.warn().log( "Cannot acquire run lock, exiting" );
663                 System.exit( 1 );
664         }
665
666                 try {
667 //            Map<String,EmailMsg> email = new HashMap<String,EmailMsg>();
668
669             try
670             {
671                 String workingDir = System.getProperty("user.dir");
672                 env.info().log( "Process jobchange file. PWD is " + workingDir );
673                 
674                 loadUsersFromRoles();
675                 loadOwnersFromNS();
676                 loadUsersFromCred();
677
678                 dumpRolesMap();
679                 dumpOwnersMap();
680                 dumpCredMap();
681                 
682                 String fname = getJobChangeDataFile();
683                 
684                 if ( fname == null )
685                 {
686                     env.warn().log("getJobChangedatafile returned null");
687                 }
688                 else
689                 {
690                     env.info().log("done with FTP");
691                 }
692                                 processJobChangeDataFile( fname, "fallout", null );
693                         }
694             catch (Exception e)
695             {
696                                 // TODO Auto-generated catch block
697                                 e.printStackTrace();
698                         }
699             
700
701                 } catch (IllegalArgumentException e) {
702             // TODO Auto-generated catch block
703             e.printStackTrace();
704                 } catch (SecurityException e) {
705             // TODO Auto-generated catch block
706             e.printStackTrace();
707                 }
708         }
709
710 /*
711     private class EmailMsg {
712         private boolean urgent = false;
713         public String url;
714         public Organization org;
715         public String summary;
716
717         public EmailMsg() {
718             org = null;
719             summary = "";
720         }
721
722         public boolean getUrgent() {
723             return( this.urgent );
724         }
725
726         public void setUrgent( boolean val ) {
727             this.urgent = val;
728         }
729         public void setOrg( Organization newOrg ) {
730             this.org = newOrg;
731         }
732         public Organization getOrg() {
733             return( this.org );
734         }
735     }
736 */
737         @Override
738         protected void _close(AuthzTrans trans) {
739         session.close();
740         }
741 }
742
743