Fix Agent and CM Issues
[aaf/authz.git] / auth / auth-certman / src / main / java / org / onap / aaf / auth / cm / service / CMService.java
index aa145f1..900df8a 100644 (file)
@@ -3,7 +3,7 @@
  * org.onap.aaf
  * ===========================================================================
  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
- * Modifications Copyright (C) 2018 IBM.
+ * Modifications Copyright (C) 2019 IBM.
  * ===========================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -80,7 +80,7 @@ public class CMService {
     // Limit total requests
     private static final int MAX_X509s = 200; // Need a "LIMIT Exception" DB.
     private static final String MAX_X509S_TAG = "cm_max_x509s"; // be able to adjust limit in future
-    
+
     public static final String REQUEST = "request";
     public static final String IGNORE_IPS = "ignoreIPs";
     public static final String RENEW = "renew";
@@ -93,6 +93,8 @@ public class CMService {
 
     private static final String[] NO_NOTES = new String[0];
     private final Permission root_read_permission;
+       private final String aaf_ns;
+
     private final CertDAO certDAO;
     private final CredDAO credDAO;
     private final ArtiDAO artiDAO;
@@ -114,8 +116,9 @@ public class CMService {
 
         this.certManager = certman;
 
+        aaf_ns = trans.getProperty(Config.AAF_ROOT_NS, Config.AAF_ROOT_NS_DEF);
         root_read_permission=new AAFPermission(
-                trans.getProperty(Config.AAF_ROOT_NS, Config.AAF_ROOT_NS_DEF),
+                aaf_ns,
                 ACCESS,
                 "*",
                 "read"
@@ -149,44 +152,32 @@ public class CMService {
 
             List<String> notes = null;
             List<String> fqdns;
+            boolean dynamic_sans = trans.fish(new AAFPermission(null, ca.getPermType(), ca.getName(),DYNAMIC_SANS));
+            boolean ignoreIPs = trans.fish(new AAFPermission(mechNS,CERTMAN, ca.getName(), IGNORE_IPS));
             boolean domain_based = false;
-            boolean dynamic_sans = false;
 
+            // Note: Many Cert Impls require FQDN in "CN=" to be in the SANS as well.  Therefore, the "fqdn" variable
+            // includes main ID plus ADDITIONAL SANS at all times.
             if(req.value.fqdns.isEmpty()) {
-               fqdns = new ArrayList<>();
+                fqdns = new ArrayList<>();
+                fqdns.add(key);
             } else {
-               // Only Template or Dynamic permitted to pass in FQDNs
-               if (req.value.fqdns.get(0).startsWith("*")) { // Domain set
+                // Only Template or Dynamic permitted to pass in FQDNs
+                if (req.value.fqdns.get(0).startsWith("*")) { // Domain set
                     if (trans.fish(new AAFPermission(null,ca.getPermType(), ca.getName(), DOMAIN))) {
-                       domain_based = true;
+                        domain_based = true;
                     } else {
                         return Result.err(Result.ERR_Denied,
                               "Domain based Authorizations (" + req.value.fqdns.get(0) + ") requires Exception");
                     }
-               } else {
-                       if(trans.fish(new AAFPermission(null, ca.getPermType(), ca.getName(),DYNAMIC_SANS))) {
-                               dynamic_sans = true;
-                       } else {
-                        return Result.err(Result.ERR_Denied,
-                            "Dynamic SANs for (" + req.value.mechid + ") requires Permission");                                
-                       }
-               }
-               fqdns = new ArrayList<>(req.value.fqdns);
+                }
+                fqdns = new ArrayList<>(req.value.fqdns);
             }
 
             String email = null;
 
             try {
                 Organization org = trans.org();
-
-                boolean ignoreIPs;
-                if(allowIgnoreIPs) {
-                    ignoreIPs = trans.fish(new AAFPermission(mechNS,CERTMAN, ca.getName(), IGNORE_IPS));
-                } else {
-                    ignoreIPs = false;
-                }
-                
-
                 InetAddress primary = null;
                 // Organize incoming information to get to appropriate Artifact
                 if (!fqdns.isEmpty()) { // Passed in FQDNS, validated above
@@ -197,8 +188,8 @@ public class CMService {
                         String domain = fqdns.get(0).substring(1); // starts with *, see above
                         fqdns.remove(0);
                         if (fqdns.isEmpty()) {
-                            return Result.err(Result.ERR_Denied, 
-                               "Requests using domain require machine declaration");
+                            return Result.err(Result.ERR_Denied,
+                                "Requests using domain require machine declaration");
                         }
 
                         if (!ignoreIPs) {
@@ -212,7 +203,7 @@ public class CMService {
                         }
 
                     } else {
-                       // Passed in FQDNs, but not starting with *
+                        // Passed in FQDNs, but not starting with *
                         if (!ignoreIPs) {
                             for (String cn : req.value.fqdns) {
                                 try {
@@ -220,7 +211,8 @@ public class CMService {
                                     Set<String> potentialSanNames = new HashSet<>();
                                     for (InetAddress ia1 : ias) {
                                         InetAddress ia2 = InetAddress.getByAddress(ia1.getAddress());
-                                        if (primary == null && ias.length == 1 && trans.ip().equals(ia1.getHostAddress())) {
+                                        String ip = trans.ip();
+                                        if (primary == null && ip.equals(ia1.getHostAddress())) {
                                             primary = ia1;
                                         } else if (!cn.equals(ia1.getHostName())
                                                 && !ia2.getHostName().equals(ia2.getHostAddress())) {
@@ -254,37 +246,37 @@ public class CMService {
                         return Result.err(Result.ERR_Denied,"Authorization must not include SANS when doing Dynamic SANS (%s, %s)", req.value.mechid, key);
                     }
                 } else {
-                       if(domain_based) {
-                           ra = artiDAO.read(trans, req.value.mechid, key);
-                           if (ra.isOKhasData()) { // is the Template available?
-                               add = ra.value.get(0);
-                               add.machine = host;
-                               for (String s : fqdns) {
-                                   if (!s.equals(add.machine)) {
-                                       add.sans(true).add(s);
-                                   }
-                               }
-                               Result<ArtiDAO.Data> rc = artiDAO.create(trans, add); // Create new Artifact from Template
-                               if (rc.notOK()) {
-                                   return Result.err(rc);
-                               }
-                           } else {
-                               return Result.err(Result.ERR_Denied,"No Authorization Template for %s, %s", req.value.mechid, key);
-                           }
-                       } else {
+                    if(domain_based) {
+                        ra = artiDAO.read(trans, req.value.mechid, key);
+                        if (ra.isOKhasData()) { // is the Template available?
+                            add = ra.value.get(0);
+                            add.machine = host;
+                            for (String s : fqdns) {
+                                if (!s.equals(add.machine)) {
+                                    add.sans(true).add(s);
+                                }
+                            }
+                            Result<ArtiDAO.Data> rc = artiDAO.create(trans, add); // Create new Artifact from Template
+                            if (rc.notOK()) {
+                                return Result.err(rc);
+                            }
+                        } else {
+                            return Result.err(Result.ERR_Denied,"No Authorization Template for %s, %s", req.value.mechid, key);
+                        }
+                    } else {
                         return Result.err(Result.ERR_Denied,"No Authorization found for %s, %s", req.value.mechid, key);
-                       }
+                    }
                 }
 
                 // Add Artifact listed FQDNs
                 if(!dynamic_sans) {
-                       if (add.sans != null) {
-                           for (String s : add.sans) {
-                               if (!fqdns.contains(s)) {
-                                   fqdns.add(s);
-                               }
-                           }
-                       }
+                    if (add.sans != null) {
+                        for (String s : add.sans) {
+                            if (!fqdns.contains(s)) {
+                                fqdns.add(s);
+                            }
+                        }
+                    }
                 }
 
                 // Policy 2: If Config marked as Expired, do not create or renew
@@ -296,16 +288,16 @@ public class CMService {
 
                 // Policy 3: MechID must be current
                 Identity muser = org.getIdentity(trans, add.mechid);
-                if (muser == null) {
-                    return Result.err(Result.ERR_Policy, "MechID must exist in %s", org.getName());
+                if (muser == null || !muser.isFound()) {
+                    return Result.err(Result.ERR_Policy, "AppID '%s' must exist in %s",add.mechid,org.getName());
                 }
 
                 // Policy 4: Sponsor must be current
                 Identity ouser = muser.responsibleTo();
-                if (ouser == null) {
+                if (ouser == null || !ouser.isFound()) {
                     return Result.err(Result.ERR_Policy, "%s does not have a current sponsor at %s", add.mechid,
                             org.getName());
-                } else if (!ouser.isFound() || ouser.mayOwn() != null) {
+                } else if (ouser.mayOwn() != null) {
                     return Result.err(Result.ERR_Policy, "%s reports that %s cannot be responsible for %s",
                             org.getName(), trans.user());
                 }
@@ -327,19 +319,28 @@ public class CMService {
                             trans.user(), mechNS);
                 }
 
+                // Policy 8: IP Addresses allowed in Certs only by Permission
+                if(!trans.fish(new AAFPermission(aaf_ns,CERTMAN, ca.getName(), "ip"))) {
+                       for(String fqdn : fqdns) {
+                       if(CA.IPV4_PATTERN.matcher(fqdn).matches() || CA.IPV6_PATTERN.matcher(fqdn).matches()) {
+                            return Result.err(Status.ERR_Denied,
+                                    "Machines include a IP Address.  IP Addresses are not allowed except by Permission");
+                       }
+                       }
+                }
+
                 // Make sure Primary is the first in fqdns
+
                 if (fqdns.size() > 1) {
                     for (int i = 0; i < fqdns.size(); ++i) {
                         if (primary==null && !ignoreIPs) {
                             trans.error().log("CMService var primary is null");
                         } else {
                             String fg = fqdns.get(i);
-                            if (fg!=null && primary!=null && fg.equals(primary.getHostName())) {
-                                if (i != 0) {
+                            if ((fg!=null && primary!=null && fg.equals(primary.getHostName()))&&(i != 0)) {
                                     String tmp = fqdns.get(0);
                                     fqdns.set(0, primary.getHostName());
                                     fqdns.set(i, tmp);
-                                }
                             }
                         }
                     }
@@ -354,7 +355,7 @@ public class CMService {
             try {
                 csrMeta = BCFactory.createCSRMeta(ca, req.value.mechid, email, fqdns);
                 csrMeta.environment(ca.getEnv());
-                
+
                 // Before creating, make sure they don't have too many
                 if(!trans.fish(limitOverridePerm)) {
                     Result<List<CertDAO.Data>> existing = certDAO.readID(trans, req.value.mechid);
@@ -366,11 +367,9 @@ public class CMService {
                             Collection<? extends Certificate> certs = Factory.toX509Certificate(cdd.x509);
                             for(Iterator<? extends Certificate> iter = certs.iterator(); iter.hasNext();) {
                                 X509Certificate x509 = (X509Certificate)iter.next();
-                                if(x509.getNotAfter().after(now) && x509.getSubjectDN().getName().contains(cn)) {
-                                    if(++count>max_509s) {
+                                if((x509.getNotAfter().after(now) && x509.getSubjectDN().getName().contains(cn))&&(++count>max_509s)) {
                                         break;
-                                    }
-                                }
+                                     }
                             }
                         }
                         if(count>max_509s) {
@@ -392,7 +391,7 @@ public class CMService {
                 cdd.id = req.value.mechid;
                 cdd.x500 = x509.getSubjectDN().getName();
                 cdd.x509 = Factory.toString(trans, x509);
-                
+
                 certDAO.create(trans, cdd);
 
                 CredDAO.Data crdd = new CredDAO.Data();