* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import org.onap.aaf.auth.dao.cass.CredDAO;
import org.onap.aaf.auth.dao.cass.UserRoleDAO;
import org.onap.aaf.auth.env.AuthzTrans;
+import org.onap.aaf.auth.org.Organization.Expiration;
import org.onap.aaf.auth.org.Organization.Identity;
import org.onap.aaf.auth.org.OrganizationException;
import org.onap.aaf.cadi.configure.Factory;
public class Analyze extends Batch {
- private static final int unknown=0;
+ private static final int unknown=0;
private static final int owner=1;
private static final int supervisor=2;
private static final int total=0;
private static final int pending=1;
private static final int approved=2;
-
-
+
+
public static final String NEED_APPROVALS = "NeedApprovals";
private static final String EXTEND = "Extend";
private static final String EXPIRED_OWNERS = "ExpiredOwners";
private static final String CSV = ".csv";
private static final String INFO = "info";
+ private static final String NOT_COMPLIANT = "NotCompliant";
private int minOwners;
private Map<String, CSV.Writer> writerList;
private ExpireRange expireRange;
private CSV.Writer deleteCW;
private CSV.Writer needApproveCW;
private CSV.Writer extendCW;
+ private CSV.Writer notCompliantCW;
private Range futureRange;
private final String sdate;
private LastNotified ln;
-
+
public Analyze(AuthzTrans trans) throws APIException, IOException, OrganizationException {
super(trans.env());
trans.info().log("Starting Connection Process");
-
+
TimeTaken tt0 = trans.start("Cassandra Initialization", Env.SUB);
try {
TimeTaken tt = trans.start("Connect to Cluster", Env.REMOTE);
} finally {
tt.done();
}
-
+
minOwners=1;
- // Create Intermediate Output
+ // Create Intermediate Output
writerList = new HashMap<>();
-
+
expireRange = new ExpireRange(trans.env().access());
sdate = Chrono.dateOnlyStamp(now);
for( List<Range> lr : expireRange.ranges.values()) {
}
}
}
-
+
// Setup New Approvals file
futureRange = expireRange.newFutureRange();
File file = new File(logDir(),NEED_APPROVALS + sdate +CSV);
needApproveCW = approveCSV.writer();
needApproveCW.row(INFO,NEED_APPROVALS,sdate,1);
writerList.put(NEED_APPROVALS,needApproveCW);
-
+
// Setup Extend Approvals file
file = new File(logDir(),EXTEND + sdate +CSV);
CSV extendCSV = new CSV(env.access(),file);
extendCW = extendCSV.writer();
extendCW.row(INFO,EXTEND,sdate,1);
writerList.put(EXTEND,extendCW);
+
+ // Setup NotCompliant Writer for Apps
+ file = new File(logDir(),NOT_COMPLIANT + sdate + CSV);
+ CSV ncCSV = new CSV(env.access(),file);
+ notCompliantCW = ncCSV.writer();
+ writerList.put(NOT_COMPLIANT, notCompliantCW);
// Load full data of the following
ln = new LastNotified(session);
protected void run(AuthzTrans trans) {
TimeTaken tt;
AuthzTrans noAvg = trans.env().newTransNoAvg();
-
+
////////////////////
// Load all Notifieds, and either add to local Data, or mark for Deletion.
ln.loadAll(noAvg,expireRange.approveDelete,deleteCW);
-
+
// Hold Good Tickets to keyed User/Role for UserRole Step
Map<String,Ticket> mur = new TreeMap<>();
try {
Approval.load(trans, session, Approval.v2_0_17);
-
+
////////////////////
final Map<UUID,Ticket> goodTickets = new TreeMap<>();
tt = trans.start("Analyze Expired Futures",Trans.SUB);
} finally {
tt.done();
}
-
+
Set<String> approvers = new TreeSet<>();
tt = trans.start("Connect Approvals with Futures",Trans.SUB);
try {
} else {
// for users and approvers still valid
String user = appr.getUser();
-
- if(org.isRevoked(noAvg, appr.getApprover())) {
- deleteCW.comment("Approver ID is revoked");
+
+ Date revokedAppr = org.isRevoked(noAvg, appr.getApprover());
+ Date revokedUser = org.isRevoked(noAvg, user);
+ if(revokedAppr!=null) {
+ deleteCW.comment("Approver ID is revoked on " + revokedAppr);
Approval.row(deleteCW, appr);
- } else if(user!=null && !user.isEmpty() && org.isRevoked(noAvg, user)) {
- deleteCW.comment("USER ID is revoked");
+ } else if(user!=null && !user.isEmpty() && revokedUser!=null) {
+ deleteCW.comment("USER ID is revoked on " + revokedUser);
Approval.row(deleteCW, appr);
} else {
ticket.approvals.add(appr); // add to found Ticket
} finally {
tt.done();
}
-
- /* Run through all Futures, and see if
+
+ /* Run through all Futures, and see if
* 1) they have been executed (no longer valid)
- * 2) The current Approvals indicate they can proceed
+ * 2) The current Approvals indicate they can proceed
*/
Map<String,Pending> pendingApprs = new HashMap<>();
Map<String,Pending> pendingTemp = new HashMap<>();
-
+
String approver;
-
+
tt = trans.start("Analyze Good Tickets",Trans.SUB);
try {
for(Ticket ticket : goodTickets.values()) {
case "user_role":
int state[][] = new int[3][3];
int type;
-
+
for(Approval appr : ticket.approvals) {
switch(appr.getType()) {
case "owner":
++state[type][unknown];
}
}
-
+
// To Approve:
// Always must have at least 1 owner
if((state[owner][total]>0 && state[owner][approved]>0) &&
// If there are no Supervisors, that's ok
- (state[supervisor][total]==0 ||
- // But if there is a Supervisor, they must have approved
+ (state[supervisor][total]==0 ||
+ // But if there is a Supervisor, they must have approved
(state[supervisor][approved]>0))) {
UserRoleDAO.Data urdd = new UserRoleDAO.Data();
try {
}
} finally {
if("user_role".equals(ticket.f.fdd.target)) {
- String key = ticket.f.fdd.target_key;
+ String key = ticket.f.fdd.target_key;
if(key!=null) {
mur.put(key, ticket);
}
}
// Good Tickets no longer needed
goodTickets.clear();
-
+
/**
* Decide to Notify about Approvals, based on activity/last Notified
*/
GregorianCalendar gc = new GregorianCalendar();
gc.add(GregorianCalendar.DAY_OF_WEEK, 5);
Date remind = gc.getTime();
-
+
for(Entry<String, Pending> es : pendingApprs.entrySet()) {
Pending p = es.getValue();
- if(p.newApprovals()
- || p.earliest() == LastNotified.NEVER // yes, equals.
+ if(p.newApprovals()
+ || p.earliest() == LastNotified.NEVER // yes, equals.
|| p.earliest().after(remind)) {
p.row(needApproveCW,es.getKey());
}
} finally {
tt.done();
}
-
+
// clear out Approval Intermediates
pendingTemp = null;
pendingApprs = null;
} finally {
}
-
+
/**
- Run through User Roles.
+ Run through User Roles.
Owners are treated specially in next section.
Regular roles are checked against Date Ranges. If match Date Range, write out to appropriate file.
- */
-
+ */
+
try {
Role.load(trans, session);
-
+
try {
tt = trans.start("Analyze UserRoles, storing Owners",Trans.SUB);
Set<String> specialCommented = new HashSet<>();
}
return;
}
+ Date revoked = org.isRevoked(trans, ur.user());
+ if(revoked!=null) {
+ GregorianCalendar gc = new GregorianCalendar();
+ gc.setTime(revoked);
+ GregorianCalendar gracePeriodEnds = org.expiration(gc, Expiration.RevokedGracePeriodEnds, ur.user());
+ if(now.after(gracePeriodEnds.getTime())) {
+ ur.row(deleteCW, UserRole.UR,"Revoked ID, no grace period left");
+ } else {
+ ur.row(notCompliantCW, UserRole.UR, "Revoked ID: WARNING! GracePeriod Ends " + Chrono.dateOnlyStamp(gracePeriodEnds));
+ }
+ return;
+ }
ur.row(deleteCW, UserRole.UR,"Not in Organization");
return;
} else if(Role.byName.get(ur.role())==null) {
ur.row(deleteCW, UserRole.UR,String.format("Role %s does not exist", ur.role()));
return;
+ // Make sure owners can still be owners.
+ } else if(ur.role().endsWith(".owner")) {
+ String err = identity.mayOwn();
+ if(err!=null) {
+ ur.row(deleteCW, UserRole.UR,String.format("%s may not be an owner: %s",ur.user(),err));
+ return;
+ }
}
+
+
+
// Just let expired UserRoles sit until deleted
- if(futureRange.inRange(ur.expires())&&(!mur.containsKey(ur.user() + '|' + ur.role()))) {
+ if(futureRange.inRange(ur.expires())&&(!mur.containsKey(ur.user() + '|' + ur.role()))) {
// Cannot just delete owners, unless there is at least one left. Process later
if ("owner".equals(ur.rname())) {
Set<UserRole> urs = owners.get(ur.role());
tt.done();
}
mur.clear();
-
+
/**
Now Process Owners, one owner Role at a time, ensuring one is left,
- preferably a good one. If so, process the others as normal.
-
+ preferably a good one. If so, process the others as normal.
+
Otherwise, write to ExpiredOwners Report
*/
tt = trans.start("Analyze Owners Separately",Trans.SUB);
final CSV ownerCSV = new CSV(env.access(),file);
CSV.Writer expOwner = ownerCSV.writer();
expOwner.row(INFO,EXPIRED_OWNERS,sdate,2);
-
+
try {
for (Set<UserRole> sur : owners.values()) {
int goodOwners = 0;
++goodOwners;
}
}
-
+
for (UserRole ur : sur) {
if (goodOwners >= minOwners) {
Range r = writeAnalysis(noAvg, ur);
Role.clear();
UserRole.clear();
}
-
+
/**
* Check for Expired Credentials
*/
try {
// Load Cred. We don't follow Visitor, because we have to gather up everything into Identity Anyway
Cred.load(trans, session);
-
+
tt = trans.start("Analyze Expired Credentials",Trans.SUB);
try {
for (Cred cred : Cred.data.values()) {
} finally {
Cred.clear();
}
-
+
////////////////////
tt = trans.start("Analyze Expired X509s",Trans.SUB);
try {
noAvg.info().log(e);
}
}
-
+
private Approval findApproval(UserRole ur) {
Approval existing = null;
List<Approval> apprs = Approval.byUser.get(ur.user());
for(Approval appr : apprs) {
if(ur.role().equals(appr.getRole()) &&
appr.getMemo().contains(Chrono.dateOnlyStamp(ur.expires()))) {
- existing = appr;
+ existing = appr;
}
}
}
} catch (OrganizationException e) {
i=null;
}
- if(r.needsContact(lnd,i)) {
+ if(r.needsContact(lnd,i)) {
CSV.Writer cw = writerList.get(r.name());
if(cw!=null) {
ur.row(cw,UserRole.UR);
}
return r;
}
-
+
private void writeAnalysis(AuthzTrans noAvg, Cred cred, Instance inst) {
if(cred!=null && inst!=null) {
Range r = expireRange.getRange("cred", inst.expires);
} catch (OrganizationException e) {
i=null;
}
- if(r.needsContact(lnd,i)) {
+ if(r.needsContact(lnd,i)) {
CSV.Writer cw = writerList.get(r.name());
if(cw!=null) {
cred.row(cw,inst);
}
}
}
-
+
@Override
protected void _close(AuthzTrans trans) {
session.close();