// external inputs: // User data (name and list of groups) // List of PublisherDid's as param to some app-function (multi-cutout, merge) // Database connection (from Settings) // For Non-authenticated requests two behaviours possible: // A, setups with configured security: return only PUBLIC data // B, setups wihtout need of security: access all data // Currently B supported: Vlkb security filters will always set UsePrincipal. // Security filters could reserve 'anonymous' user for non-authenticated requests, if needed. // So missing UserPrincipal is interpreted as setup without security filters - full access allowed. import java.util.logging.Logger; import java.io.PrintWriter; import java.security.Principal; import java.util.List; import java.util.ArrayList; import java.util.LinkedList; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.HashSet; import java.util.Arrays; import java.util.ListIterator; public class AuthPolicy { private static final Logger LOGGER = Logger.getLogger(AuthPolicy.class.getName()); enum Access { PUBLIC_ONLY, PUBLIC_AND_AUTHORIZED_PRIVATE }; private Access access; private String userName; private String[] userGroups; private boolean userGroupsValid; private String dbConnUrl; private String dbUserName; private String dbPassword; public AuthPolicy(String userName, String[] userGroups) { this.userName = userName; this.userGroups = userGroups; this.userGroupsValid = true; access = Access.PUBLIC_AND_AUTHORIZED_PRIVATE; LOGGER.finer("User [Groups]: " + userName + " [ " + String.join(" ", userGroups) + " ]" ); } public AuthPolicy(Principal principal) { if(principal == null) { access = Access.PUBLIC_ONLY; userName = null; userGroups = null; userGroupsValid = false; LOGGER.finer("Non authenticated request (UserPrincipal null in HttpServletRequest)"); } else { if(principal instanceof VlkbUser) { VlkbUser vlkbUser = (VlkbUser) principal; userName = vlkbUser.getName(); userGroups = vlkbUser.getGroupsAsArray(); userGroupsValid = true; access = Access.PUBLIC_AND_AUTHORIZED_PRIVATE; LOGGER.finer("User [Groups]: " + userName + " [ " + String.join(" ", userGroups) + " ]" ); } else { userName = principal.getName(); LOGGER.finer("DBG principal not instance of VlkbUser, but has user-name: " + userName); userGroups = new String[]{""};//{"VLKB.groupA", "AllPrivate"}; // was for shiro userGroupsValid = true; access = Access.PUBLIC_AND_AUTHORIZED_PRIVATE; //throw new IllegalArgumentException("UserPrincipal is not of expected type"); } } } public String getUserName() { return userName; } public boolean getUserGroupsValid() { return userGroupsValid; } public String[] getUserGroups() { return userGroups; } public String getUserGroupsSqlFormat() { if( (userGroups != null) && (userGroups.length > 0) ) { return "\"" + String.join("\",\"" , userGroups) + "\""; } else { return null; } } public String getUserGroupsAsString(String separator) { if( (userGroups != null) && (userGroups.length > 0) ) { return String.join(separator, userGroups); } else { return null; } } public String getAccessPolicy() { return access.name(); // returns enum as string } public void toXML(PrintWriter writer) { writer.println("<AccessPolicy>" + this.getAccessPolicy() + "</AccessPolicy>"); String ug = getUserGroupsAsString(" "); if(userName != null) writer.println("<UserName>" + userName + "</UserName>"); if(ug != null) writer.println("<GroupNames>" + ug + "</GroupNames>"); } public String[] filterAuthorized(String[] pubdidArr, String dbConnUrl, String dbUserName, String dbPassword) { //this.dbConnUrl = dbConnUrl; this.dbUserName = dbUserName; this.dbPassword = dbPassword; LOGGER.finer("with String[] trace"); return filterAuthorized(new ArrayList<String>(Arrays.asList(pubdidArr)), dbConnUrl); } private String[] filterAuthorized(ArrayList<String> pubdidList, String dbConnUrl) { LOGGER.fine("with List <String> trace"); switch(access) { case PUBLIC_ONLY : filterNotPublic(pubdidList, dbConnUrl); break; case PUBLIC_AND_AUTHORIZED_PRIVATE : filterNotAuthorized(pubdidList, dbConnUrl); break; default : assert false : "Unrecoginzed access : " + access; } return pubdidList.toArray(new String[0]); } private void filterNotPublic(ArrayList<String> pubdids, String dbConnUrl) { LOGGER.fine("trace"); assert pubdids != null; LOGGER.finer("PublisherDID list original : " + String.join(" ", pubdids)); List<AuthPolicyDb.PubdidGroups> privateUniqPubdids = db_queryPrivateUniqPubdidGroups(dbConnUrl, pubdids); List<String> notAuthorizedUniqPubdids = pubdidsNotPublic(privateUniqPubdids, userGroups); LOGGER.finest("AuthZ removes: " + String.join(" ", notAuthorizedUniqPubdids)); removeNotAuthorized(pubdids, notAuthorizedUniqPubdids); LOGGER.finest("PublisherDID list filtered : " + (pubdids.isEmpty() ? "" : String.join(" ", pubdids))); } private List<String> pubdidsNotPublic(List<AuthPolicyDb.PubdidGroups> pubdidList, String[] userGroups) { LOGGER.fine("trace"); LOGGER.finer("userGroups: " + String.join(" ",userGroups)); List<String> pubdidsNotAuthorizedList = new LinkedList<String>(); ListIterator<AuthPolicyDb.PubdidGroups> it = pubdidList.listIterator(); while (it.hasNext()) { AuthPolicyDb.PubdidGroups pubdidGroups = it.next(); LOGGER.finest(pubdidGroups.pubdid + " : " + String.join(" ",pubdidGroups.groups)); if( true )// isIntersectionEmpty(pubdidGroups.groups, userGroups) ) { pubdidsNotAuthorizedList.add(pubdidGroups.pubdid); } } return pubdidsNotAuthorizedList; } private void filterNotAuthorized(ArrayList<String> pubdids, String dbConnUrl) { LOGGER.fine("trace"); assert pubdids != null; LOGGER.finer("PublisherDID list original : " + String.join(" ", pubdids)); List<AuthPolicyDb.PubdidGroups> privateUniqPubdids = db_queryPrivateUniqPubdidGroups(dbConnUrl, pubdids); List<String> notAuthorizedUniqPubdids = pubdidsNotAuthorized(privateUniqPubdids, userGroups); LOGGER.finest("AuthZ removes: " + String.join(" ", notAuthorizedUniqPubdids)); removeNotAuthorized(pubdids, notAuthorizedUniqPubdids); LOGGER.finest("PublisherDID list filtered : " + (pubdids.isEmpty() ? "" : String.join(" ", pubdids))); } private void removeNotAuthorized(ArrayList<String> pubdids, List<String> notAuthorizedUniqPubdids) { ListIterator<String> itr = pubdids.listIterator(); while (itr.hasNext()) { String pubdid = itr.next(); for(String notAuthPubdid : notAuthorizedUniqPubdids) { if (pubdid.equals(notAuthPubdid)) itr.remove(); } } return; } private List<AuthPolicyDb.PubdidGroups> db_queryPrivateUniqPubdidGroups(String dbConnUrl, List<String> pubdids) { AuthPolicyDb adb; synchronized(AuthPolicyDb.class) { //AuthPolicyDb.dbConnUrl = this.dbConnUrl; AuthPolicyDb.dbUserName = this.dbUserName; AuthPolicyDb.dbPassword = this.dbPassword; adb = new AuthPolicyDb(); } Set<String> uniqPubdids = new HashSet<String>(pubdids); if(uniqPubdids.isEmpty()) { List<AuthPolicyDb.PubdidGroups> privatePubdidGroups = Collections.emptyList(); return privatePubdidGroups; } else { // FIXME handle DB-exceptions List<AuthPolicyDb.PubdidGroups> privatePubdidGroups = adb.queryGroupsPrivateOnly(uniqPubdids); return privatePubdidGroups; } } private List<String> pubdidsNotAuthorized(List<AuthPolicyDb.PubdidGroups> pubdidList, String[] userGroups) { LOGGER.fine("trace"); //LOGGER.finer("userGroups: " + String.join(" ",userGroups)); List<String> pubdidsNotAuthorizedList = new LinkedList<String>(); ListIterator<AuthPolicyDb.PubdidGroups> it = pubdidList.listIterator(); while (it.hasNext()) { AuthPolicyDb.PubdidGroups pubdidGroups = it.next(); LOGGER.finest(pubdidGroups.pubdid + " : " + String.join(" ",pubdidGroups.groups)); if( isIntersectionEmpty(pubdidGroups.groups, userGroups) ) { pubdidsNotAuthorizedList.add(pubdidGroups.pubdid); } } return pubdidsNotAuthorizedList; } private boolean isIntersectionEmpty(String[] stringsA, String[] stringsB) { for(String strA : stringsA) for(String strB : stringsB) { if(strA.equals(strB)) { return false; } } return true; } }