Created
November 16, 2010 23:43
-
-
Save gschueler/702744 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/core/src/java/com/dtolabs/rundeck/core/authorization/providers/Policies.java b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/Policies.java | |
index bbe8b2b..7979ab0 100644 | |
--- a/core/src/java/com/dtolabs/rundeck/core/authorization/providers/Policies.java | |
+++ b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/Policies.java | |
@@ -16,50 +16,22 @@ | |
package com.dtolabs.rundeck.core.authorization.providers; | |
-import java.io.File; | |
-import java.io.FileNotFoundException; | |
-import java.io.FileReader; | |
-import java.io.FilenameFilter; | |
-import java.io.IOException; | |
-import java.io.PrintStream; | |
-import java.util.ArrayList; | |
-import java.util.Arrays; | |
-import java.util.Collections; | |
-import java.util.HashMap; | |
-import java.util.HashSet; | |
-import java.util.Iterator; | |
-import java.util.List; | |
-import java.util.Map; | |
-import java.util.Set; | |
-import java.util.regex.Pattern; | |
- | |
-import javax.naming.InvalidNameException; | |
-import javax.naming.ldap.LdapName; | |
-import javax.security.auth.Subject; | |
-import javax.xml.namespace.NamespaceContext; | |
-import javax.xml.parsers.DocumentBuilder; | |
-import javax.xml.parsers.DocumentBuilderFactory; | |
-import javax.xml.parsers.ParserConfigurationException; | |
-import javax.xml.xpath.XPath; | |
-import javax.xml.xpath.XPathConstants; | |
-import javax.xml.xpath.XPathExpression; | |
-import javax.xml.xpath.XPathExpressionException; | |
-import javax.xml.xpath.XPathFactory; | |
- | |
-import org.w3c.dom.DOMException; | |
-import org.w3c.dom.Document; | |
+import com.dtolabs.rundeck.core.authorization.Attribute; | |
+import com.dtolabs.rundeck.core.authorization.Explanation; | |
+import com.dtolabs.rundeck.core.authorization.Explanation.Code; | |
import org.w3c.dom.NamedNodeMap; | |
import org.w3c.dom.Node; | |
import org.w3c.dom.NodeList; | |
-import org.xml.sax.InputSource; | |
-import org.xml.sax.SAXException; | |
-import com.dtolabs.rundeck.core.authentication.Group; | |
-import com.dtolabs.rundeck.core.authentication.LdapGroup; | |
-import com.dtolabs.rundeck.core.authentication.Username; | |
-import com.dtolabs.rundeck.core.authorization.Attribute; | |
-import com.dtolabs.rundeck.core.authorization.Explanation; | |
-import com.dtolabs.rundeck.core.authorization.Explanation.Code; | |
+import javax.security.auth.Subject; | |
+import javax.xml.namespace.NamespaceContext; | |
+import javax.xml.parsers.ParserConfigurationException; | |
+import javax.xml.xpath.*; | |
+import java.io.File; | |
+import java.io.IOException; | |
+import java.io.PrintStream; | |
+import java.util.*; | |
+import java.util.regex.Pattern; | |
/** | |
* Policies represent the policies as described in the policies file(s). | |
@@ -68,25 +40,27 @@ import com.dtolabs.rundeck.core.authorization.Explanation.Code; | |
*/ | |
public class Policies { | |
- private static final String NS_AD = "http://dtolabs.com/rundeck/activedirectory"; | |
- private static final String NS_LDAP = "http://dtolabs.com/rundeck/ldap"; | |
- private final XPath xpath = XPathFactory.newInstance().newXPath(); | |
+ static final String NS_AD = "http://dtolabs.com/rundeck/activedirectory"; | |
+ static final String NS_LDAP = "http://dtolabs.com/rundeck/ldap"; | |
+ private static final XPath xpath = XPathFactory.newInstance().newXPath(); | |
private final List<File> policyFiles = new ArrayList<File>(); | |
- private final List<Document> aclpolicies = new ArrayList<Document>(); | |
- | |
+ | |
private final XPathExpression count; | |
private final XPathExpression allPolicies; | |
private final XPathExpression byUserName; | |
private final XPathExpression byGroup; | |
+ private PoliciesCache cache; | |
+ | |
- public Policies() { | |
+ public Policies(final PoliciesCache cache) { | |
+ this.cache = cache; | |
xpath.setNamespaceContext(new NamespaceContext() { | |
- | |
+ | |
@SuppressWarnings("rawtypes") | |
public Iterator getPrefixes(String namespaceURI) { return null; } | |
public String getPrefix(String namespaceURI) { return null; } | |
- | |
+ | |
public String getNamespaceURI(String prefix) { | |
if(prefix.equals("ldap")) { | |
return NS_LDAP; | |
@@ -97,7 +71,7 @@ public class Policies { | |
} | |
} | |
}); | |
- | |
+ | |
try { | |
this.count = xpath.compile("count(//policy)"); | |
this.allPolicies = xpath.compile("//policy"); | |
@@ -106,34 +80,18 @@ public class Policies { | |
} catch (XPathExpressionException e) { | |
throw new IllegalArgumentException(e); | |
} | |
- | |
- | |
- } | |
- | |
- public void add(File file) throws SAXException, IOException, ParserConfigurationException { | |
- | |
- /* Just checking to make sure it's a well formed document. */ | |
- DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); | |
- domFactory.setNamespaceAware(true); | |
- DocumentBuilder builder = domFactory.newDocumentBuilder(); | |
- aclpolicies.add(builder.parse(file)); | |
- | |
- this.policyFiles.add(file); | |
- } | |
- | |
- public void remove(File file) { | |
- this.policyFiles.remove(file); | |
} | |
public int count() { | |
int count = 0; | |
- for(Document f : aclpolicies) { | |
+ for(PoliciesDocument f : cache) { | |
+ | |
try { | |
- Double n = (Double)this.count.evaluate(f, XPathConstants.NUMBER); | |
+ Double n = f.countPolicies(); | |
count += n; | |
} catch (XPathExpressionException e) { | |
// TODO squash | |
- } | |
+ } | |
} | |
return count; | |
} | |
@@ -145,21 +103,13 @@ public class Policies { | |
* @throws PoliciesParseException Thrown when there is a problem parsing a file. | |
*/ | |
public static Policies load(File rootPath) throws IOException, PoliciesParseException { | |
- | |
- Policies p = new Policies(); | |
- | |
- for(File f : rootPath.listFiles(new FilenameFilter(){ | |
- public boolean accept(File dir, String name) { | |
- return name.endsWith(".aclpolicy"); | |
- }})) { | |
- try { | |
- p.add(f); | |
- } catch (SAXException e) { | |
- throw new PoliciesParseException(e); | |
- } catch (ParserConfigurationException e) { | |
- throw new PoliciesParseException(e); | |
- } | |
- } | |
+ | |
+ Policies p = null; | |
+ try { | |
+ p = new Policies(new PoliciesCache(rootPath)); | |
+ } catch (ParserConfigurationException e) { | |
+ throw new PoliciesParseException(e); | |
+ } | |
return p; | |
} | |
@@ -167,95 +117,9 @@ public class Policies { | |
public List<Context> narrowContext(Subject subject, Set<Attribute> environment) { | |
List<Context> matchedContexts = new ArrayList<Context>(); | |
- for(Document f : aclpolicies) { | |
+ for(final PoliciesDocument f : cache) { | |
try { | |
- NodeList policiesToEvaluate = (NodeList)this.allPolicies.evaluate(f, XPathConstants.NODESET); | |
- for(int i = 0; i < policiesToEvaluate.getLength(); i++) { | |
- | |
- Node policy = policiesToEvaluate.item(i); | |
- | |
- // What constitutes a match? | |
- // * The username matches exactly 1 in the context. | |
- // * 1 subject group matches 1 group. non disjoint sets. | |
- // | |
- // First match stops the search. | |
- | |
- // TODO: time of day check. | |
- | |
- long userMatchStart = System.currentTimeMillis(); | |
- NodeList usernames = (NodeList) this.byUserName.evaluate(policy, XPathConstants.NODESET); | |
- | |
- Set<String> policyUsers = new HashSet<String>(usernames.getLength()); | |
- for(int u = 0; u < usernames.getLength(); u++) { | |
- Node username = usernames.item(u); | |
- policyUsers.add(username.getNodeValue()); | |
- } | |
- | |
- Set<Username> userPrincipals = subject.getPrincipals(Username.class); | |
- if(userPrincipals.size() > 0) { | |
- Set<String> usernamePrincipals = new HashSet<String>(); | |
- for(Username username: userPrincipals) { | |
- usernamePrincipals.add(username.getName()); | |
- } | |
- | |
- if(!Collections.disjoint(policyUsers, usernamePrincipals)) { | |
- matchedContexts.add(new Context(policy)); | |
- System.err.println("Policy: " + i + " Matched on User: " + (System.currentTimeMillis() - userMatchStart) + "ms"); | |
- break; | |
- } | |
- } | |
- System.err.println("Policy: " + i + " No match on User: " + (System.currentTimeMillis() - userMatchStart) + "ms"); | |
- | |
- | |
- Set<Group> groupPrincipals = subject.getPrincipals(Group.class); | |
- if(groupPrincipals.size() > 0) { | |
- // no username matched, check groups. | |
- long groupCollectStart = System.currentTimeMillis(); | |
- NodeList groups = (NodeList) this.byGroup.evaluate(policy, XPathConstants.NODESET); | |
- Set<Object> policyGroups = new HashSet<Object>(groups.getLength()); | |
- for(int g = 0; g < groups.getLength(); g++) { | |
- Node group = groups.item(g); | |
- String ns = group.getNamespaceURI(); | |
- if(ns == null) { | |
- policyGroups.add(group.getNodeValue()); | |
- } else if (NS_LDAP.equalsIgnoreCase(ns) || NS_AD.equalsIgnoreCase(ns)) { | |
- try { | |
- policyGroups.add(new LdapName(group.getNodeValue())); | |
- } catch (InvalidNameException e) { | |
- // TODO Auto-generated catch block | |
- e.printStackTrace(); | |
- } catch (DOMException e) { | |
- // TODO Auto-generated catch block | |
- e.printStackTrace(); | |
- } | |
- } | |
- } | |
- Set<Object> groupNames = new HashSet<Object>(); | |
- for(Group groupPrincipal: groupPrincipals) { | |
- if(groupPrincipal instanceof LdapGroup) { | |
- try { | |
- groupNames.add(new LdapName(groupPrincipal.getName())); | |
- } catch (InvalidNameException e) { | |
- // TODO Auto-generated catch block | |
- e.printStackTrace(); | |
- } | |
- } else { | |
- groupNames.add(groupPrincipal.getName()); | |
- } | |
- } | |
- | |
- long collectDuration = System.currentTimeMillis() - groupCollectStart; | |
- if(!Collections.disjoint(policyGroups, groupNames)) { | |
- matchedContexts.add(new Context(policy)); | |
- System.err.println("matched on group. " + collectDuration + "ms"); | |
- continue; | |
- } | |
- } | |
- | |
-// if(subject.getPrincipals(LdapGroupPrincipal.class).size() > 0) { | |
-// //todo check against ldap. | |
-// } | |
- } | |
+ matchedContexts.addAll(f.matchedContexts(subject, environment)); | |
} catch (XPathExpressionException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
@@ -312,7 +176,7 @@ public class Policies { | |
final static private Map<String, XPathExpression> commandFilterCache = new HashMap<String, XPathExpression>(); | |
- public class Context { | |
+ public static class Context { | |
public Context(Node policy) { | |
super(); | |
this.policy = policy; | |
@@ -504,24 +368,16 @@ public class Policies { | |
@Deprecated | |
public List<String> listAllRoles() { | |
List<String> results = new ArrayList<String>(); | |
- for(Document f: aclpolicies) { | |
+ for(PoliciesDocument f: cache) { | |
try { | |
+ results.addAll(f.groupNames()); | |
- NodeList groups = (NodeList) xpath.evaluate("//by/group/@ldap:name | //by/group/@name", | |
- f, XPathConstants.NODESET); | |
- | |
- for(int i = 0; i < groups.getLength(); i++) { | |
- | |
- String result = groups.item(i).getNodeValue(); | |
- if(result == null || result.length() <= 0) continue; | |
- results.add(result); | |
- } | |
} catch (XPathExpressionException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
- | |
+ | |
return results; | |
} | |
} | |
diff --git a/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PoliciesCache.java b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PoliciesCache.java | |
new file mode 100644 | |
index 0000000..0236bfa | |
--- /dev/null | |
+++ b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PoliciesCache.java | |
@@ -0,0 +1,160 @@ | |
+/* | |
+ * Copyright 2010 DTO Labs, Inc. (http://dtolabs.com) | |
+ * | |
+ * 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. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+/* | |
+* PoliciesCache.java | |
+* | |
+* User: Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+* Created: Nov 16, 2010 11:26:12 AM | |
+* | |
+*/ | |
+package com.dtolabs.rundeck.core.authorization.providers; | |
+ | |
+import org.w3c.dom.Document; | |
+import org.xml.sax.SAXException; | |
+ | |
+import javax.xml.parsers.DocumentBuilder; | |
+import javax.xml.parsers.DocumentBuilderFactory; | |
+import javax.xml.parsers.ParserConfigurationException; | |
+import java.io.File; | |
+import java.io.FilenameFilter; | |
+import java.io.IOException; | |
+import java.util.Arrays; | |
+import java.util.HashMap; | |
+import java.util.Iterator; | |
+ | |
+/** | |
+ * PoliciesCache retains PolicyDocument objects for inserted Files, and reloads them if file modification time changes. | |
+ * | |
+ * @author Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+ */ | |
+public class PoliciesCache implements Iterable<PoliciesDocument> { | |
+ static final FilenameFilter filenameFilter = new FilenameFilter() { | |
+ public boolean accept(File dir, String name) { | |
+ return name.endsWith(".aclpolicy"); | |
+ } | |
+ }; | |
+ private HashMap<File, PoliciesDocument> cache = new HashMap<File, PoliciesDocument>(); | |
+ private HashMap<File, Long> expiry = new HashMap<File, Long>(); | |
+ private DocumentBuilder builder; | |
+ private File rootDir; | |
+ | |
+ public PoliciesCache(File rootDir) throws ParserConfigurationException { | |
+ this.rootDir = rootDir; | |
+ DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); | |
+ domFactory.setNamespaceAware(true); | |
+ builder = domFactory.newDocumentBuilder(); | |
+ } | |
+ | |
+ private File[] listDirFiles() { | |
+ return rootDir.listFiles(filenameFilter); | |
+ } | |
+ | |
+ public synchronized void add(final File file) throws PoliciesParseException { | |
+ PoliciesDocument doc = getDocument(file); | |
+ } | |
+ | |
+ private PoliciesDocument createEntry(final File file) throws PoliciesParseException { | |
+ try { | |
+ final Document document = builder.parse(file); | |
+ return new PoliciesDocument(document,file); | |
+ } catch (SAXException e) { | |
+ throw new PoliciesParseException(e); | |
+ } catch (IOException e) { | |
+ throw new PoliciesParseException(e); | |
+ } | |
+ } | |
+ | |
+ public synchronized PoliciesDocument getDocument(final File file) throws PoliciesParseException { | |
+ if(!file.exists()) { | |
+ expiry.remove(file); | |
+ cache.remove(file); | |
+ return null; | |
+ } | |
+ final long lastmod = file.lastModified(); | |
+ final Long cachetime = expiry.get(file); | |
+ final PoliciesDocument entry; | |
+ if (null == cachetime || lastmod > cachetime) { | |
+ entry = createEntry(file); | |
+ if (null != entry) { | |
+ expiry.put(file, lastmod); | |
+ cache.put(file, entry); | |
+ } | |
+ } else { | |
+ entry = cache.get(file); | |
+ } | |
+ return entry; | |
+ } | |
+ | |
+ public Iterator<PoliciesDocument> iterator() { | |
+ return new cacheIterator(Arrays.asList(listDirFiles()).iterator()); | |
+ } | |
+ | |
+ /** | |
+ * Iterator over the PoliciesDocuments for the cache's files. It skips | |
+ * files that cannot be loaded. | |
+ */ | |
+ private class cacheIterator implements Iterator<PoliciesDocument> { | |
+ Iterator<File> intIter; | |
+ private File nextFile; | |
+ private PoliciesDocument nextDocument; | |
+ | |
+ public cacheIterator(final Iterator<File> intIter) { | |
+ this.intIter = intIter; | |
+ nextFile = this.intIter.hasNext() ? this.intIter.next() : null; | |
+ loadNextDocument(); | |
+ } | |
+ | |
+ private void loadNextDocument() { | |
+ while (hasNextFile() && null == nextDocument) { | |
+ try { | |
+ nextDocument = getDocument(getNextFile()); | |
+ } catch (PoliciesParseException e) { | |
+ | |
+ } | |
+ } | |
+ } | |
+ | |
+ private File getNextFile() { | |
+ File next = nextFile; | |
+ nextFile = intIter.hasNext() ? intIter.next() : null; | |
+ return next; | |
+ } | |
+ | |
+ private PoliciesDocument getNextDocument() { | |
+ PoliciesDocument doc = nextDocument; | |
+ nextDocument=null; | |
+ loadNextDocument(); | |
+ return doc; | |
+ } | |
+ | |
+ public boolean hasNextFile() { | |
+ return null != nextFile; | |
+ } | |
+ | |
+ public boolean hasNext() { | |
+ return null != nextDocument; | |
+ } | |
+ | |
+ public PoliciesDocument next() { | |
+ return getNextDocument(); | |
+ } | |
+ | |
+ public void remove() { | |
+ } | |
+ } | |
+ | |
+} | |
diff --git a/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PoliciesDocument.java b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PoliciesDocument.java | |
new file mode 100644 | |
index 0000000..fcabc48 | |
--- /dev/null | |
+++ b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PoliciesDocument.java | |
@@ -0,0 +1,219 @@ | |
+/* | |
+ * Copyright 2010 DTO Labs, Inc. (http://dtolabs.com) | |
+ * | |
+ * 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. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+/* | |
+* PoliciesDocument.java | |
+* | |
+* User: Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+* Created: Nov 16, 2010 12:01:02 PM | |
+* | |
+*/ | |
+package com.dtolabs.rundeck.core.authorization.providers; | |
+ | |
+import com.dtolabs.rundeck.core.authentication.Group; | |
+import com.dtolabs.rundeck.core.authentication.LdapGroup; | |
+import com.dtolabs.rundeck.core.authentication.Username; | |
+import com.dtolabs.rundeck.core.authorization.Attribute; | |
+import org.w3c.dom.Document; | |
+import org.w3c.dom.Node; | |
+import org.w3c.dom.NodeList; | |
+ | |
+import javax.naming.InvalidNameException; | |
+import javax.naming.ldap.LdapName; | |
+import javax.security.auth.Subject; | |
+import javax.xml.xpath.*; | |
+import javax.xml.namespace.NamespaceContext; | |
+import java.io.File; | |
+import java.util.*; | |
+ | |
+ | |
+/** | |
+ * PoliciesDocument wraps a Document and | |
+ * | |
+ * @author Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+ */ | |
+public class PoliciesDocument { | |
+ private Document document; | |
+ private File file; | |
+ private ArrayList<String> groupNames; | |
+ private ArrayList<Policy> policies; | |
+ private Double count=null; | |
+ private static final XPath xpath = XPathFactory.newInstance().newXPath(); | |
+ | |
+ public static final XPathExpression countXpath; | |
+ public static final XPathExpression allPolicies; | |
+ public static final XPathExpression policyByUserName; | |
+ public static final XPathExpression policyByGroup; | |
+ public static final XPathExpression allGroups; | |
+ | |
+ static { | |
+ xpath.setNamespaceContext(new NamespaceContext() { | |
+ | |
+ @SuppressWarnings ("rawtypes") | |
+ public Iterator getPrefixes(String namespaceURI) { | |
+ return null; | |
+ } | |
+ | |
+ public String getPrefix(String namespaceURI) { | |
+ return null; | |
+ } | |
+ | |
+ public String getNamespaceURI(String prefix) { | |
+ if (prefix.equals("ldap")) { | |
+ return Policies.NS_LDAP; | |
+ } else if (prefix.equals("ActiveDirectory")) { | |
+ return Policies.NS_AD; | |
+ } else { | |
+ return ""; // 1.6 = XMLConstants.NULL_NS_URI; | |
+ } | |
+ } | |
+ }); | |
+ try { | |
+ countXpath = xpath.compile("count(//policy)"); | |
+ allPolicies = xpath.compile("//policy"); | |
+ policyByUserName = xpath.compile("by/user/@username"); | |
+ policyByGroup = xpath.compile("by/group/@name | by/group/@ldap:name"); | |
+ allGroups = xpath.compile("//by/group/@name | //by/group/@ldap:name"); | |
+ } catch (XPathExpressionException e) { | |
+ throw new IllegalArgumentException(e); | |
+ } | |
+ | |
+ } | |
+ | |
+ public PoliciesDocument(final Document document, final File file) { | |
+ this.document = document; | |
+ this.file=file; | |
+ } | |
+ | |
+ public Collection<String> groupNames() throws XPathExpressionException { | |
+ if (null != groupNames) { | |
+ return groupNames; | |
+ } | |
+ groupNames = new ArrayList<String>(); | |
+ NodeList groups = (NodeList) allGroups.evaluate(document, XPathConstants.NODESET); | |
+ for (int i = 0 ; i < groups.getLength() ; i++) { | |
+ String result = groups.item(i).getNodeValue(); | |
+ if (result == null || result.length() <= 0) { | |
+ continue; | |
+ } | |
+ groupNames.add(result); | |
+ } | |
+ return groupNames; | |
+ } | |
+ | |
+ public Double countPolicies() throws XPathExpressionException { | |
+ if (null != count) { | |
+ return count; | |
+ } | |
+ count = (Double) countXpath.evaluate(document, XPathConstants.NUMBER); | |
+ return count; | |
+ } | |
+ | |
+ private Collection<Policy> listPolicies() throws XPathExpressionException { | |
+ if (null != policies) { | |
+ return policies; | |
+ } | |
+ policies = new ArrayList<Policy>(); | |
+ | |
+ NodeList policiesToEvaluate = (NodeList) allPolicies.evaluate(document, XPathConstants.NODESET); | |
+ for (int i = 0 ; i < policiesToEvaluate.getLength() ; i++) { | |
+ | |
+ Node policy = policiesToEvaluate.item(i); | |
+ policies.add(new PolicyNode(policy)); | |
+ } | |
+ return policies; | |
+ } | |
+ | |
+ public Collection<Policies.Context> matchedContexts(Subject subject, Set<Attribute> environment) throws | |
+ XPathExpressionException { | |
+ ArrayList<Policies.Context> matchedContexts = new ArrayList<Policies.Context>(); | |
+ int i = 0; | |
+ for (final Policy policy : listPolicies()) { | |
+ | |
+ | |
+ // What constitutes a match? | |
+ // * The username matches exactly 1 in the context. | |
+ // * 1 subject group matches 1 group. non disjoint sets. | |
+ // | |
+ // First match stops the search. | |
+ | |
+ // TODO: time of day check. | |
+ | |
+ long userMatchStart = System.currentTimeMillis(); | |
+ | |
+ | |
+ Set<Username> userPrincipals = subject.getPrincipals(Username.class); | |
+ if (userPrincipals.size() > 0) { | |
+ Set<String> policyUsers = policy.getUsernames(); | |
+ Set<String> usernamePrincipals = new HashSet<String>(); | |
+ for (Username username : userPrincipals) { | |
+ usernamePrincipals.add(username.getName()); | |
+ } | |
+ | |
+ if (!Collections.disjoint(policyUsers, usernamePrincipals)) { | |
+ matchedContexts.add(policy.getContext()); | |
+ System.err.println( | |
+ "Policy: " + i + " Matched on User: " + (System.currentTimeMillis() - userMatchStart) + "ms"); | |
+ break; | |
+ } | |
+ } | |
+ System.err.println( | |
+ "Policy: " + i + " No match on User: " + (System.currentTimeMillis() - userMatchStart) + "ms"); | |
+ | |
+ | |
+ Set<Group> groupPrincipals = subject.getPrincipals(Group.class); | |
+ if (groupPrincipals.size() > 0) { | |
+ // no username matched, check groups. | |
+ long groupCollectStart = System.currentTimeMillis(); | |
+ | |
+ Set<Object> policyGroups = policy.getGroups(); | |
+ Set<Object> groupNames = new HashSet<Object>(); | |
+ for (Group groupPrincipal : groupPrincipals) { | |
+ if (groupPrincipal instanceof LdapGroup) { | |
+ try { | |
+ groupNames.add(new LdapName(groupPrincipal.getName())); | |
+ } catch (InvalidNameException e) { | |
+ // TODO Auto-generated catch block | |
+ e.printStackTrace(); | |
+ } | |
+ } else { | |
+ groupNames.add(groupPrincipal.getName()); | |
+ } | |
+ } | |
+ | |
+ long collectDuration = System.currentTimeMillis() - groupCollectStart; | |
+ if (!Collections.disjoint(policyGroups, groupNames)) { | |
+ matchedContexts.add(policy.getContext()); | |
+ System.err.println("matched on group. " + collectDuration + "ms"); | |
+ continue; | |
+ } | |
+ } | |
+ | |
+// if(subject.getPrincipals(LdapGroupPrincipal.class).size() > 0) { | |
+// //todo check against ldap. | |
+// } | |
+ i++; | |
+ } | |
+ return matchedContexts; | |
+ } | |
+ | |
+ @Override | |
+ public String toString() { | |
+ return "PoliciesDocument{" + | |
+ "file=" + file + | |
+ '}'; | |
+ } | |
+} | |
diff --git a/core/src/java/com/dtolabs/rundeck/core/authorization/providers/Policy.java b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/Policy.java | |
new file mode 100644 | |
index 0000000..dbedb8f | |
--- /dev/null | |
+++ b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/Policy.java | |
@@ -0,0 +1,39 @@ | |
+/* | |
+ * Copyright 2010 DTO Labs, Inc. (http://dtolabs.com) | |
+ * | |
+ * 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. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+/* | |
+* Policy.java | |
+* | |
+* User: Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+* Created: Nov 16, 2010 12:31:26 PM | |
+* | |
+*/ | |
+package com.dtolabs.rundeck.core.authorization.providers; | |
+ | |
+import java.util.Set; | |
+ | |
+/** | |
+ * Policy is ... | |
+ * | |
+ * @author Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+ */ | |
+public interface Policy { | |
+ public Set<String> getUsernames(); | |
+ | |
+ Policies.Context getContext(); | |
+ | |
+ public Set<Object> getGroups(); | |
+} | |
diff --git a/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PolicyNode.java b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PolicyNode.java | |
new file mode 100644 | |
index 0000000..6b2a21b | |
--- /dev/null | |
+++ b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/PolicyNode.java | |
@@ -0,0 +1,103 @@ | |
+/* | |
+ * Copyright 2010 DTO Labs, Inc. (http://dtolabs.com) | |
+ * | |
+ * 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. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+/* | |
+* Policy.java | |
+* | |
+* User: Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+* Created: Nov 16, 2010 12:00:32 PM | |
+* | |
+*/ | |
+package com.dtolabs.rundeck.core.authorization.providers; | |
+ | |
+import org.w3c.dom.Node; | |
+import org.w3c.dom.NodeList; | |
+import org.w3c.dom.DOMException; | |
+ | |
+import javax.xml.xpath.XPathConstants; | |
+import javax.xml.xpath.XPathExpressionException; | |
+import javax.naming.ldap.LdapName; | |
+import javax.naming.InvalidNameException; | |
+import java.util.HashSet; | |
+import java.util.Set; | |
+ | |
+/** | |
+ * PolicyNode provides the Policy interface on top of a DOM Node | |
+ * | |
+ * @author Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+ */ | |
+public class PolicyNode implements Policy { | |
+ Node policyNode; | |
+ HashSet<String> usernames; | |
+ Set<Object> groups; | |
+ | |
+ public PolicyNode(Node policyNode) throws XPathExpressionException { | |
+ this.policyNode = policyNode; | |
+ init(); | |
+ } | |
+ | |
+ public Set<String> getUsernames() { | |
+ return usernames; | |
+ } | |
+ | |
+ private void init() throws XPathExpressionException { | |
+ initUsernames(); | |
+ initGroups(); | |
+ } | |
+ | |
+ private void initGroups() throws XPathExpressionException { | |
+ NodeList groupNodes = (NodeList) PoliciesDocument.policyByGroup.evaluate(policyNode, XPathConstants.NODESET); | |
+ groups = new HashSet<Object>(groupNodes.getLength()); | |
+ for (int g = 0 ; g < groupNodes.getLength() ; g++) { | |
+ Node group = groupNodes.item(g); | |
+ String ns = group.getNamespaceURI(); | |
+ if (ns == null) { | |
+ groups.add(group.getNodeValue()); | |
+ } else if (Policies.NS_LDAP.equalsIgnoreCase(ns) || Policies.NS_AD.equalsIgnoreCase(ns)) { | |
+ try { | |
+ groups.add(new LdapName(group.getNodeValue())); | |
+ } catch (InvalidNameException e) { | |
+ // TODO Auto-generated catch block | |
+ e.printStackTrace(); | |
+ } catch (DOMException e) { | |
+ // TODO Auto-generated catch block | |
+ e.printStackTrace(); | |
+ } | |
+ } | |
+ } | |
+ | |
+ } | |
+ | |
+ private void initUsernames() throws XPathExpressionException { | |
+ | |
+ NodeList usernameNodes = (NodeList) PoliciesDocument.policyByUserName.evaluate(policyNode, | |
+ XPathConstants.NODESET); | |
+ | |
+ usernames = new HashSet<String>(usernameNodes.getLength()); | |
+ for (int u = 0 ; u < usernameNodes.getLength() ; u++) { | |
+ Node username = usernameNodes.item(u); | |
+ usernames.add(username.getNodeValue()); | |
+ } | |
+ } | |
+ | |
+ public Policies.Context getContext() { | |
+ return new Policies.Context(policyNode); | |
+ } | |
+ | |
+ public Set<Object> getGroups() { | |
+ return groups; | |
+ } | |
+} | |
diff --git a/core/src/java/com/dtolabs/rundeck/core/authorization/providers/SAREAuthorization.java b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/SAREAuthorization.java | |
index 5530db4..86ab967 100644 | |
--- a/core/src/java/com/dtolabs/rundeck/core/authorization/providers/SAREAuthorization.java | |
+++ b/core/src/java/com/dtolabs/rundeck/core/authorization/providers/SAREAuthorization.java | |
@@ -249,7 +249,6 @@ public class SAREAuthorization implements Authorization { | |
public Explanation explain() { | |
return explanation; | |
} | |
- @Override | |
public long evaluationDuration() { | |
return evaluationTime; | |
} | |
diff --git a/core/src/test/com/dtolabs/rundeck/core/authorization/providers/TestPoliciesCache.java b/core/src/test/com/dtolabs/rundeck/core/authorization/providers/TestPoliciesCache.java | |
new file mode 100644 | |
index 0000000..7970c4d | |
--- /dev/null | |
+++ b/core/src/test/com/dtolabs/rundeck/core/authorization/providers/TestPoliciesCache.java | |
@@ -0,0 +1,88 @@ | |
+/* | |
+ * Copyright 2010 DTO Labs, Inc. (http://dtolabs.com) | |
+ * | |
+ * 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. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package com.dtolabs.rundeck.core.authorization.providers; | |
+/* | |
+* TestPoliciesCache.java | |
+* | |
+* User: Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+* Created: Nov 16, 2010 1:32:37 PM | |
+* | |
+*/ | |
+ | |
+import junit.framework.Test; | |
+import junit.framework.TestCase; | |
+import junit.framework.TestSuite; | |
+ | |
+import java.io.File; | |
+import java.net.URISyntaxException; | |
+import java.net.URL; | |
+import java.util.ArrayList; | |
+import java.util.Iterator; | |
+ | |
+public class TestPoliciesCache extends TestCase { | |
+ PoliciesCache policiesCache; | |
+ | |
+ public TestPoliciesCache(String name) { | |
+ super(name); | |
+ } | |
+ | |
+ public static Test suite() { | |
+ return new TestSuite(TestPoliciesCache.class); | |
+ } | |
+ | |
+ | |
+ public void setUp() throws Exception { | |
+ policiesCache = new PoliciesCache(getPath("com/dtolabs/rundeck/core/authorization")); | |
+ } | |
+ | |
+ /** | |
+ * @return | |
+ */ | |
+ public static File getPath(String name) { | |
+ | |
+ URL url = ClassLoader.getSystemResource(name); | |
+ File f; | |
+ try { | |
+ f = new File(url.toURI()); | |
+ } catch (URISyntaxException e) { | |
+ f = new File(url.getPath()); | |
+ } | |
+ return f; | |
+ } | |
+ | |
+ | |
+ protected void tearDown() throws Exception { | |
+ } | |
+ | |
+ public static void main(String args[]) { | |
+ junit.textui.TestRunner.run(suite()); | |
+ } | |
+ | |
+ | |
+ public void testIterator() throws Exception { | |
+ final Iterator<PoliciesDocument> iterator = policiesCache.iterator(); | |
+ assertNotNull(iterator); | |
+ assertTrue(iterator.hasNext()); | |
+ ArrayList<PoliciesDocument> docs = new ArrayList<PoliciesDocument>(); | |
+ while(iterator.hasNext()) { | |
+ final PoliciesDocument policiesDocument = iterator.next(); | |
+ assertNotNull(policiesDocument); | |
+ docs.add(policiesDocument); | |
+ } | |
+ assertEquals(2, docs.size()); | |
+ } | |
+} | |
\ No newline at end of file | |
diff --git a/core/src/test/com/dtolabs/rundeck/core/authorization/providers/TestPoliciesDocument.java b/core/src/test/com/dtolabs/rundeck/core/authorization/providers/TestPoliciesDocument.java | |
new file mode 100644 | |
index 0000000..baccd88 | |
--- /dev/null | |
+++ b/core/src/test/com/dtolabs/rundeck/core/authorization/providers/TestPoliciesDocument.java | |
@@ -0,0 +1,92 @@ | |
+/* | |
+ * Copyright 2010 DTO Labs, Inc. (http://dtolabs.com) | |
+ * | |
+ * 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. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ */ | |
+ | |
+package com.dtolabs.rundeck.core.authorization.providers; | |
+/* | |
+* TestPoliciesDocument.java | |
+* | |
+* User: Greg Schueler <a href="mailto:greg@dtosolutions.com">greg@dtosolutions.com</a> | |
+* Created: Nov 16, 2010 1:31:59 PM | |
+* | |
+*/ | |
+ | |
+import junit.framework.Test; | |
+import junit.framework.TestCase; | |
+import junit.framework.TestSuite; | |
+import org.w3c.dom.Document; | |
+ | |
+import javax.xml.parsers.DocumentBuilder; | |
+import javax.xml.parsers.DocumentBuilderFactory; | |
+import java.io.File; | |
+import java.net.URISyntaxException; | |
+import java.net.URL; | |
+import java.util.Collection; | |
+ | |
+public class TestPoliciesDocument extends TestCase { | |
+ PoliciesDocument policiesDocument; | |
+ File testdir; | |
+ File test1; | |
+ File test2; | |
+ private DocumentBuilder builder; | |
+ | |
+ public TestPoliciesDocument(String name) { | |
+ super(name); | |
+ } | |
+ | |
+ public static Test suite() { | |
+ return new TestSuite(TestPoliciesDocument.class); | |
+ } | |
+ | |
+ public void setUp() throws Exception { | |
+ testdir = getPath("com/dtolabs/rundeck/core/authorization"); | |
+ test1 = new File(testdir, "test1.aclpolicy"); | |
+ test2 = new File(testdir, "admintest.aclpolicy"); | |
+ DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); | |
+ domFactory.setNamespaceAware(true); | |
+ builder = domFactory.newDocumentBuilder(); | |
+ } | |
+ | |
+ /** | |
+ * @return | |
+ */ | |
+ public static File getPath(String name) { | |
+ | |
+ URL url = ClassLoader.getSystemResource(name); | |
+ File f; | |
+ try { | |
+ f = new File(url.toURI()); | |
+ } catch (URISyntaxException e) { | |
+ f = new File(url.getPath()); | |
+ } | |
+ return f; | |
+ } | |
+ | |
+ protected void tearDown() throws Exception { | |
+ } | |
+ | |
+ public static void main(String args[]) { | |
+ junit.textui.TestRunner.run(suite()); | |
+ } | |
+ | |
+ | |
+ public void testPoliciesDocument() throws Exception { | |
+ final Document document = builder.parse(test1); | |
+ PoliciesDocument doc = new PoliciesDocument(document, test1); | |
+ assertEquals(5.0, doc.countPolicies()); | |
+ final Collection<String> groupNames = doc.groupNames(); | |
+ assertEquals(6, groupNames.size()); | |
+ } | |
+} | |
\ No newline at end of file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment