AT&T 2.0.19 Code drop, stage 3
[aaf/authz.git] / auth / auth-batch / src / main / java / org / onap / aaf / auth / update / NotifyCredExpiring.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.Collections;
29 import java.util.Comparator;
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Map.Entry;
35
36 import org.onap.aaf.auth.Batch;
37 import org.onap.aaf.auth.BatchPrincipal;
38 import org.onap.aaf.auth.actions.Email;
39 import org.onap.aaf.auth.actions.EmailPrint;
40 import org.onap.aaf.auth.actions.Message;
41 import org.onap.aaf.auth.dao.cass.CredDAO;
42 import org.onap.aaf.auth.dao.hl.Question;
43 import org.onap.aaf.auth.env.AuthzTrans;
44 import org.onap.aaf.auth.helpers.Cred;
45 import org.onap.aaf.auth.helpers.Notification;
46 import org.onap.aaf.auth.helpers.UserRole;
47 import org.onap.aaf.auth.helpers.Notification.TYPE;
48 import org.onap.aaf.auth.layer.Result;
49 import org.onap.aaf.auth.org.EmailWarnings;
50 import org.onap.aaf.auth.org.Organization;
51 import org.onap.aaf.auth.org.OrganizationException;
52 import org.onap.aaf.auth.org.OrganizationFactory;
53 import org.onap.aaf.auth.org.Organization.Identity;
54 import org.onap.aaf.misc.env.APIException;
55 import org.onap.aaf.misc.env.Env;
56 import org.onap.aaf.misc.env.TimeTaken;
57 import org.onap.aaf.misc.env.util.Chrono;
58
59 import java.util.TreeMap;
60
61
62 public class NotifyCredExpiring extends Batch {
63
64         private static final String UNKNOWN_ID = "unknown@deprecated.id";
65         private static final String AAF_INSTANTIATED_MECHID = "AAF INSTANTIATED MECHID";
66         private static final String EXPIRATION_DATE = "EXPIRATION DATE";
67         private static final String QUICK_LINK = "QUICK LINK TO UPDATE PAGE";
68         private static final String DASH_1 = "-----------------------";
69         private static final String DASH_2 = "---------------";
70         private static final String DASH_3 = "----------------------------------------------------";
71         private static final String LINE = "\n----------------------------------------------------------------";
72         private Email email;
73         private int maxEmails;
74         private final PrintStream ps;
75         private final AuthzTrans noAvg;
76         private String supportEmailAddr;
77
78         public NotifyCredExpiring(AuthzTrans trans) throws APIException, IOException, OrganizationException {
79                 super(trans.env());
80                 TimeTaken tt = trans.start("Connect to Cluster", Env.REMOTE);
81                 try {
82                         session = cluster.connect();
83                 } finally {
84                         tt.done();
85                 }
86                 
87                 noAvg = env.newTransNoAvg();
88                 noAvg.setUser(new BatchPrincipal("batch:NotifyCredExpiring"));
89                 
90                 if((supportEmailAddr = env.getProperty("mailFromUserId"))==null) {
91                         throw new APIException("mailFromUserId property must be set");
92                 }
93                 if(isDryRun()) {
94                         email = new EmailPrint();
95                         maxEmails=3;
96                         maxEmails = Integer.parseInt(trans.getProperty("MAX_EMAILS","3"));
97                 } else {
98                         email = new Email();
99                         maxEmails = Integer.parseInt(trans.getProperty("MAX_EMAILS","3"));
100                 }
101                 
102                 email.subject("AAF Password Expiration Notification (ENV: %s)",batchEnv);
103                 email.preamble("AAF (MOTS 22830) is the AT&T Authorization System used by many AT&T Tools and Applications.\n\n" +
104                                 "  The following Credentials are expiring on the dates shown. Failure to act before the expiration date "
105                                 + "will cause your App's Authentications to fail.\n");
106                 email.signature("Sincerely,\nAAF Team (Our MOTS# 22830)\n"
107                                 + "https://wiki.web.att.com/display/aaf/Contact+Us\n"
108                                 + "(Use 'Other Misc Requests (TOPS)')");
109
110                 Cred.load(trans, session,CredDAO.BASIC_AUTH, CredDAO.BASIC_AUTH_SHA256);
111                 Notification.load(trans, session, Notification.v2_0_18);
112                 UserRole.load(trans, session, UserRole.v2_0_11);
113                 
114                 ps = new PrintStream(new FileOutputStream(logDir() + "/email"+Chrono.dateOnlyStamp()+".log",true));
115                 ps.printf("### Approval Notify %s for %s%s\n",Chrono.dateTime(),batchEnv,dryRun?", DryRun":"");
116         }
117         
118         @Override
119         protected void run(AuthzTrans trans) {
120                 
121                 EmailWarnings ewp = org.emailWarningPolicy();
122                 long now = System.currentTimeMillis();
123                 Date early = new Date(now+(ewp.credExpirationWarning()*2)); // 2 months back
124                 Date must = new Date(now+ewp.credExpirationWarning()); // 1 months back
125                 Date critical = new Date(now+ewp.emailUrgentWarning()); // 1 week
126                 Date within2Weeks = new Date(now+604800000 * 2);
127                 Date withinLastWeek = new Date(now-604800000);
128                 Date tooLate = new Date(now);
129                 
130                 // Temp structures
131                 Map<String,Cred> lastCred = new HashMap<String,Cred>();
132                 Map<String,List<LastCred>> ownerCreds = new TreeMap<String,List<LastCred>>();
133                 Date last;
134                 
135
136                 List<LastCred> noOwner = new ArrayList<LastCred>();
137                 ownerCreds.put(UNKNOWN_ID,noOwner);
138
139                 // Get a list of ONLY the ones needing email by Owner
140                 for(Entry<String, List<Cred>> es : Cred.byNS.entrySet()) {
141                         lastCred.clear();
142                         for(Cred c : es.getValue()) {
143                                 last = c.last(CredDAO.BASIC_AUTH,CredDAO.BASIC_AUTH_SHA256);
144                                 if(last!=null && last.after(tooLate) && last.before(early)) {
145                                         List<UserRole> ownerURList = UserRole.byRole.get(es.getKey()+".owner");
146                                         if(ownerURList!=null) {
147                                                 for(UserRole ur:ownerURList) {
148                                                         String owner = ur.user();
149                                                         List<LastCred> llc = ownerCreds.get(owner);
150                                                         if(llc==null) {
151                                                                 ownerCreds.put(owner, (llc=new ArrayList<LastCred>()));
152                                                         }
153                                                         llc.add(new LastCred(c,last));
154                                                 }
155                                         } else {
156                                                 noOwner.add(new LastCred(c,last));
157                                         }
158                                 }
159                         }
160                 }
161                 
162                 boolean bCritical,bNormal,bEarly;
163                 int emailCount=0;
164                 Message msg = new Message();
165                 Notification ownNotf;
166                 StringBuilder logMessage = new StringBuilder();
167                 for(Entry<String,List<LastCred>> es : ownerCreds.entrySet()) {
168                         String owner = es.getKey();
169                         boolean header = true;
170                         try {
171                                 Organization org = OrganizationFactory.obtain(env, owner);
172                                 Identity user = org.getIdentity(noAvg, owner);
173                                 if(!UNKNOWN_ID.equals(owner) && user==null) {
174                                         ps.printf("Invalid Identity: %s\n", owner);
175                                 } else {
176                                         logMessage.setLength(0);
177                                         if(maxEmails>emailCount) {
178                                                 bCritical=bNormal=bEarly = false;
179                                                 email.clear();
180                                                 msg.clear();
181                                                 email.addTo(user==null?supportEmailAddr:user.email());
182
183                                                 ownNotf = Notification.get(es.getKey(),TYPE.CN);
184                                                 if(ownNotf==null) {
185                                                         ownNotf = Notification.create(user==null?UNKNOWN_ID:user.fullID(), TYPE.CN);
186                                                 }
187                                                 last = ownNotf.last;
188                                                 // Get Max ID size for formatting purposes
189                                                 int length = AAF_INSTANTIATED_MECHID.length();
190                                                 for(LastCred lc : es.getValue()) {
191                                                         length = Math.max(length, lc.cred.id.length());
192                                                 }
193                                                 String id_exp_fmt = "\t%-"+length+"s  %15s  %s";
194
195                                                 Collections.sort(es.getValue(),LastCred.COMPARE);
196                                                 for(LastCred lc : es.getValue()) {
197                                                         if(lc.last.after(must) && lc.last.before(early) && 
198                                                                 (ownNotf.last==null || ownNotf.last.before(withinLastWeek))) {
199                                                                 if(!bEarly && header) {
200                                                                         msg.line("\tThe following are friendly 2 month reminders, just in case you need to schedule your updates early.  "
201                                                                                         + "You will be reminded next month\n");
202                                                                         msg.line(id_exp_fmt, AAF_INSTANTIATED_MECHID,EXPIRATION_DATE, QUICK_LINK);
203                                                                         msg.line(id_exp_fmt, DASH_1, DASH_2, DASH_3);
204                                                                         header = false;
205                                                                 }
206                                                                 bEarly = true;
207                                                         } else if(lc.last.after(critical) && lc.last.before(must) && 
208                                                                         (ownNotf.last==null || ownNotf.last.before(withinLastWeek))) {
209                                                                 if(!bNormal) {
210                                                                         boolean last2wks = lc.last.before(within2Weeks);
211                                                                         if(last2wks) {
212                                                                                 try {
213                                                                                         Identity supvsr = user.responsibleTo();
214                                                                                         email.addCC(supvsr.email());
215                                                                                 } catch(OrganizationException e) {
216                                                                                         trans.error().log(e, "Supervisor cannot be looked up");
217                                                                                 }
218                                                                         }
219                                                                         if(header) {
220                                                                                 msg.line("\tIt is now important for you to update Passwords all all configurations using them for the following.\n" +
221                                                                                                 (last2wks?"\tNote: Your Supervisor is CCd\n":"\tNote: Your Supervisor will be notified if this is not being done before the last 2 weeks\n"));
222                                                                                 msg.line(id_exp_fmt, AAF_INSTANTIATED_MECHID,EXPIRATION_DATE, QUICK_LINK);
223                                                                                 msg.line(id_exp_fmt, DASH_1, DASH_2, DASH_3);
224                                                                         }
225                                                                         header = false;
226                                                                 }
227                                                                 bNormal=true;
228                                                         } else if(lc.last.after(tooLate) && lc.last.before(critical)) { // Email Every Day, with Supervisor
229                                                                 if(!bCritical && header) {
230                                                                         msg.line("\t!!! WARNING: These Credentials will expire in LESS THAN ONE WEEK !!!!\n" +
231                                                                                          "\tYour supervisor is added to this Email\n");
232                                                                         msg.line(id_exp_fmt, AAF_INSTANTIATED_MECHID,EXPIRATION_DATE, QUICK_LINK);
233                                                                         msg.line(id_exp_fmt, DASH_1, DASH_2, DASH_3);
234                                                                         header = false;
235                                                                 }
236                                                                 bCritical = true;
237                                                                 try {
238                                                                         if(user!=null) {
239                                                                                 Identity supvsr = user.responsibleTo();
240                                                                                 if(supvsr!=null) {
241                                                                                         email.addCC(supvsr.email());
242                                                                                         supvsr = supvsr.responsibleTo();
243                                                                                         if(supvsr!=null) {
244                                                                                                 email.addCC(supvsr.email());
245                                                                                         }
246                                                                                 }
247                                                                         }
248                                                                 } catch(OrganizationException e) {
249                                                                         trans.error().log(e, "Supervisor cannot be looked up");
250                                                                 }
251                                                         }
252                                                         if(bEarly || bNormal || bCritical) {
253                                                                 if(logMessage.length()==0) {
254                                                                         logMessage.append("NotifyCredExpiring");
255                                                                 }
256                                                                 logMessage.append("\n\t");
257                                                                 logMessage.append(lc.cred.id);
258                                                                 logMessage.append('\t');
259                                                                 logMessage.append(Chrono.dateOnlyStamp(lc.last));
260                                                                 msg.line(id_exp_fmt, lc.cred.id, Chrono.dateOnlyStamp(lc.last)+"     ",env.getProperty(GUI_URL)+"/creddetail?ns="+Question.domain2ns(lc.cred.id));
261                                                         }
262                                                 }
263                                                 
264                                                 if(bEarly || bNormal || bCritical) {
265                                                         msg.line(LINE);
266                                                         msg.line("Why are you receiving this Notification?\n");
267                                                                 msg.line("You are the listed owner of one or more AAF Namespaces. ASPR requires that those responsible for "
268                                                                                 + "applications and their access review them regularly for accuracy.  The AAF WIKI page for AT&T is https://wiki.web.att.com/display/aaf.  "
269                                                                                 + "You might like https://wiki.web.att.com/display/aaf/AAF+in+a+Nutshell.  More detailed info regarding questions of being a Namespace Owner is available at https://wiki.web.att.com/pages/viewpage.action?pageId=594741363\n");
270                                                                 msg.line("You may view the Namespaces you listed as Owner for in this AAF Env by viewing the following webpage:\n");
271                                                                 msg.line("   %s/ns\n\n",env.getProperty(GUI_URL));
272                                                         email.msg(msg);
273                                                         Result<Void> rv = email.exec(trans, org,"");
274                                                         if(rv.isOK()) {
275                                                                 ++emailCount;
276                                                                 if(!isDryRun()) {
277                                                                         ownNotf.update(noAvg, session, false);
278                                                                         // SET LastNotification
279                                                                 }
280                                                                 email.log(ps,logMessage.toString());
281                                                         } else {
282                                                                 trans.error().log(rv.errorString());
283                                                         }
284                                                 }
285                                         }
286                                 }
287                         } catch (OrganizationException e) {
288                                 trans.info().log(e);
289                         }
290                 }
291                 trans.info().printf("%d emails sent for %s", emailCount,batchEnv);
292         }
293         
294         private static class LastCred {
295                 public Cred cred; 
296                 public Date last;
297                 
298                 public LastCred(Cred cred, Date last) {
299                         this.cred = cred;
300                         this.last = last;
301                 }
302                 
303                 // Reverse Sort (Oldest on top)
304                 public static Comparator<LastCred> COMPARE = new Comparator<LastCred>() {
305                         @Override
306                         public int compare(LastCred o1, LastCred o2) {
307                                 return o2.last.compareTo(o1.last);
308                         }
309                 };
310                 
311                 public String toString() {
312                         return Chrono.dateTime(last) + cred.toString();
313                 }
314         }
315         
316         @Override
317         protected void _close(AuthzTrans trans) {
318             session.close();
319                 ps.close();
320         }
321 }