Mass removal of all Tabs (Style Warnings)
[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<>();
132         Map<String,List<LastCred>> ownerCreds = new TreeMap<>();
133         Date last;
134         
135
136         List<LastCred> noOwner = new ArrayList<>();
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.getByRole().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<>()));
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 }