Collection syntax change because of Sonar
[aaf/authz.git] / auth / auth-batch / src / main / java / org / onap / aaf / auth / update / NotifyApprovals.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.FileOutputStream;
25 import java.io.IOException;
26 import java.io.PrintStream;
27 import java.util.ArrayList;
28 import java.util.Date;
29 import java.util.GregorianCalendar;
30 import java.util.List;
31 import java.util.Map.Entry;
32
33 import org.onap.aaf.auth.Batch;
34 import org.onap.aaf.auth.BatchPrincipal;
35 import org.onap.aaf.auth.actions.Email;
36 import org.onap.aaf.auth.actions.EmailPrint;
37 import org.onap.aaf.auth.actions.Message;
38 import org.onap.aaf.auth.dao.CassAccess;
39 import org.onap.aaf.auth.dao.cass.ApprovalDAO;
40 import org.onap.aaf.auth.dao.cass.FutureDAO;
41 import org.onap.aaf.auth.dao.cass.HistoryDAO;
42 import org.onap.aaf.auth.env.AuthzTrans;
43 import org.onap.aaf.auth.helpers.Approval;
44 import org.onap.aaf.auth.helpers.Future;
45 import org.onap.aaf.auth.org.Organization;
46 import org.onap.aaf.auth.org.OrganizationException;
47 import org.onap.aaf.auth.org.OrganizationFactory;
48 import org.onap.aaf.auth.org.Organization.Identity;
49 import org.onap.aaf.misc.env.APIException;
50 import org.onap.aaf.misc.env.util.Chrono;
51
52 public class NotifyApprovals extends Batch {
53         private static final String LINE = "----------------------------------------------------------------";
54         private final HistoryDAO historyDAO;
55         private final ApprovalDAO apprDAO;
56         private final FutureDAO futureDAO;
57         private Email email;
58         private int maxEmails;
59         private final PrintStream ps;
60         private final AuthzTrans noAvg;
61
62         public NotifyApprovals(AuthzTrans trans) throws APIException, IOException, OrganizationException {
63                 super(trans.env());
64                 
65                 noAvg = env.newTransNoAvg();
66                 noAvg.setUser(new BatchPrincipal("batch:NotifyApprovals"));
67
68                 historyDAO = new HistoryDAO(trans, cluster, CassAccess.KEYSPACE);
69                 session = historyDAO.getSession(trans);
70                 apprDAO = new ApprovalDAO(trans, historyDAO);
71                 futureDAO = new FutureDAO(trans, historyDAO);
72                 if(isDryRun()) {
73                         email = new EmailPrint();
74                         maxEmails=3;
75                 } else {
76                         email = new Email();
77                         maxEmails = Integer.parseInt(trans.getProperty("MAX_EMAILS","3"));
78                 }
79                 email.subject("AAF Approval Notification (ENV: %s)",batchEnv);
80                 email.preamble("AAF (MOTS 22830) is the AT&T Authorization System used by many AT&T Tools and Applications." +
81                                 "\n  Your approval is required, which you may enter on the following page:"
82                                 + "\n\n\t%s/approve\n\n"
83                                 ,env.getProperty(GUI_URL));
84                 email.signature("Sincerely,\nAAF Team (Our MOTS# 22830)\n"
85                                 + "https://wiki.web.att.com/display/aaf/Contact+Us\n"
86                                 + "(Use 'Other Misc Requests (TOPS)')");
87
88                 Approval.load(trans, session, Approval.v2_0_17);
89                 Future.load(trans, session, Future.v2_0_17); // Skip the Construct Data
90                 
91                 ps = new PrintStream(new FileOutputStream(logDir() + "/email"+Chrono.dateOnlyStamp()+".log",true));
92                 ps.printf("### Approval Notify %s for %s%s\n",Chrono.dateTime(),batchEnv,dryRun?", DryRun":"");
93         }
94
95         @Override
96         protected void run(AuthzTrans trans) {
97                 GregorianCalendar gc = new GregorianCalendar();
98                 Date now = gc.getTime();
99                 String today = Chrono.dateOnlyStamp(now);
100                 gc.add(GregorianCalendar.MONTH, -1);
101                 gc=null;
102
103
104                 Message msg = new Message();
105                 int emailCount = 0;
106                 List<Approval> pending = new ArrayList<>();
107                 boolean isOwner,isSupervisor;
108                 for(Entry<String, List<Approval>> es : Approval.byApprover.entrySet()) {
109                         isOwner = isSupervisor = false;
110                         String approver = es.getKey();
111                         if(approver.indexOf('@')<0) {
112                                 approver += org.getRealm();
113                         }
114                         Date latestNotify=null, soonestExpire=null;
115                         GregorianCalendar latest=new GregorianCalendar();
116                         GregorianCalendar soonest=new GregorianCalendar();
117                         pending.clear();
118                         
119                         for(Approval app : es.getValue()) {
120                                 Future f = app.getTicket()==null?null:Future.data.get(app.getTicket());
121                                 if(f==null) { // only Ticketed Approvals are valid.. the others are records.
122                                         // Approvals without Tickets are no longer valid. 
123                                         if("pending".equals(app.getStatus())) {
124                                                 app.setStatus("lapsed");
125                                                 app.update(noAvg,apprDAO,dryRun); // obeys dryRun
126                                         }
127                                 } else {
128                                         if((soonestExpire==null && f.expires()!=null) || (soonestExpire!=null && f.expires()!=null && soonestExpire.before(f.expires()))) {
129                                                 soonestExpire=f.expires();
130                                         }
131
132                                         if("pending".equals(app.getStatus())) {
133                                                 if(!isOwner) {
134                                                         isOwner = "owner".equals(app.getType());
135                                                 }
136                                                 if(!isSupervisor) {
137                                                         isSupervisor = "supervisor".equals(app.getType());
138                                                 }
139
140                                                 if((latestNotify==null && app.getLast_notified()!=null) ||(latestNotify!=null && app.getLast_notified()!=null && latestNotify.before(app.getLast_notified()))) {
141                                                         latestNotify=app.getLast_notified();
142                                                 }
143                                                 pending.add(app);
144                                         }
145                                 }
146                         }
147
148                         if(!pending.isEmpty()) {
149                                 boolean go = false;
150                                 if(latestNotify==null) { // never notified... make it so
151                                         go=true;
152                                 } else {
153                                         if(!today.equals(Chrono.dateOnlyStamp(latest))) { // already notified today
154                                                 latest.setTime(latestNotify);
155                                                 soonest.setTime(soonestExpire);
156                                                 int year;
157                                                 int days = soonest.get(GregorianCalendar.DAY_OF_YEAR)-latest.get(GregorianCalendar.DAY_OF_YEAR);
158                                                 days+=((year=soonest.get(GregorianCalendar.YEAR))-latest.get(GregorianCalendar.YEAR))*365 + 
159                                                                 (soonest.isLeapYear(year)?1:0);
160                                                 if(days<7) { // If Expirations get within a Week (or expired), notify everytime.
161                                                         go = true;
162                                                 }
163                                         }
164                                 }
165                                 if(go) {
166                                         if(maxEmails>emailCount++) {
167                                                 try {
168                                                         Organization org = OrganizationFactory.obtain(env, approver);
169                                                         Identity user = org.getIdentity(noAvg, approver);
170                                                         if(user==null) {
171                                                                 ps.printf("Invalid Identity: %s\n", approver);
172                                                         } else {
173                                                                 email.clear();
174                                                                 msg.clear();
175                                                                 email.addTo(user.email());
176                                                                 msg.line(LINE);
177                                                                 msg.line("Why are you receiving this Notification?\n");
178                                                                 if(isSupervisor) {
179                                                                         msg.line("%sYou are the supervisor of one or more employees who need access to tools which are protected by AAF.  " + 
180                                                                                          "Your employees may ask for access to various tools and applications to do their jobs.  ASPR requires "
181                                                                                          + "that you are notified and approve their requests. The details of each need is provided when you click "
182                                                                                          + "on webpage above.\n",isOwner?"1) ":"");
183                                                                         msg.line("Your participation in this process fulfills the ASPR requirement to re-authorize users in roles on a regular basis.\n\n");
184                                                                 }
185                                                         
186                                                                 if(isOwner) {
187                                                                         msg.line("%sYou are the listed owner of one or more AAF Namespaces. ASPR requires that those responsible for "
188                                                                                         + "applications and their access review them regularly for accuracy.  The AAF WIKI page for AT&T is https://wiki.web.att.com/display/aaf.  "
189                                                                                         + "More info regarding questions of being a Namespace Owner is available at https://wiki.web.att.com/pages/viewpage.action?pageId=594741363\n",isSupervisor?"2) ":"");
190                                                                         msg.line("Additionally, Credentials attached to the Namespace must be renewed regularly.  While you may delegate certain functions to " + 
191                                                                                          "Administrators within your Namespace, you are ultimately responsible to make sure credentials do not expire.\n");
192                                                                         msg.line("You may view the Namespaces you listed as Owner for in this AAF Env by viewing the following webpage:\n");
193                                                                         msg.line("   %s/ns\n\n",env.getProperty(GUI_URL));
194                                                                 
195                                                                 }
196                                                                 msg.line("  If you are unfamiliar with AAF, you might like to peruse the following links:"
197                                                                                 + "\n\thttps://wiki.web.att.com/display/aaf/AAF+in+a+Nutshell"
198                                                                                 + "\n\thttps://wiki.web.att.com/display/aaf/The+New+Person%%27s+Guide+to+AAF");
199                                                                 msg.line("\n  SPECIAL NOTE about SWM Management Groups: Understand that SWM management Groups correlate one-to-one to AAF Namespaces. "
200                                                                                 + "(SWM uses AAF for the Authorization piece of Management Groups).  You may be assigned the SWM Management Group by asking "
201                                                                                 + "directly, or through any of the above stated automated processes.  Auto-generated Namespaces typically look like 'com.att.44444.PROD' "
202                                                                                 + "where '44444' is a MOTS ID, and 'PROD' is PROD|DEV|TEST, etc.  For your convenience, the MOTS link is http://ebiz.sbc.com/mots.\n");
203                                                                 msg.line("  Finally, realize that there are automated processes which create Machines and Resources via SWM, Kubernetes or other "
204                                                                                 + "such tooling.  If you or your predecessor requested them, you were set as the owner of the AAF Namespace created during "
205                                                                                 + "that process.\n");
206                                                                 msg.line("  For ALL QUESTIONS of why and how of SWM, and whether you or your reports can be removed, please contact SWM at "
207                                                                                 + "https://wiki.web.att.com/display/swm/Support\n");
208
209                                                                 email.msg(msg);
210                                                                 email.exec(noAvg, org,"");
211                                                                 if(!isDryRun()) {
212                                                                         email.log(ps,"NotifyApprovals");
213                                                                         for(Approval app : pending) {
214                                                                                 app.setLastNotified(now);
215                                                                                 app.update(noAvg, apprDAO, dryRun);
216                                                                         }
217                                                                 }
218                                                         }
219                                                 } catch (OrganizationException e) {
220                                                         trans.info().log(e);
221                                                 }
222                                         }
223                                 }
224                         }
225                 }
226                 trans.info().printf("%d emails sent for %s", emailCount,batchEnv);
227         }
228         
229         @Override
230         protected void _close(AuthzTrans trans) {
231                 futureDAO.close(trans);
232                 apprDAO.close(trans);
233                 historyDAO.close(trans);
234                 ps.close();
235         }
236 }