/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.sun.jini.discovery.internal; import java.util.Arrays; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.security.auth.x500.X500Principal; import net.jini.core.constraint.ClientAuthentication; import net.jini.core.constraint.ClientMaxPrincipal; import net.jini.core.constraint.ClientMaxPrincipalType; import net.jini.core.constraint.ClientMinPrincipal; import net.jini.core.constraint.ClientMinPrincipalType; import net.jini.core.constraint.Confidentiality; import net.jini.core.constraint.ConstraintAlternatives; import net.jini.core.constraint.Delegation; import net.jini.core.constraint.DelegationAbsoluteTime; import net.jini.core.constraint.DelegationRelativeTime; import net.jini.core.constraint.Integrity; import net.jini.core.constraint.InvocationConstraint; import net.jini.core.constraint.InvocationConstraints; import net.jini.core.constraint.ServerAuthentication; import net.jini.core.constraint.ServerMinPrincipal; import net.jini.io.UnsupportedConstraintException; /** * Processes constraints specified to net.jini.discovery.x500.* discovery * format providers. */ class X500Constraints { private static final Object SUPPORTED = new Object(); private static final Object UNSUPPORTED = new Object(); private static final Set supportedRequestConstraints; private static final Set supportedAnnouncementConstraints; static { Collection baseSupported = Arrays.asList(new Object[]{ Confidentiality.NO, Delegation.NO, DelegationAbsoluteTime.class, DelegationRelativeTime.class, Integrity.YES }); supportedRequestConstraints = new HashSet(baseSupported); supportedRequestConstraints.add(ClientAuthentication.YES); supportedRequestConstraints.add(ServerAuthentication.NO); supportedAnnouncementConstraints = new HashSet(baseSupported); supportedAnnouncementConstraints.add(ClientAuthentication.NO); supportedAnnouncementConstraints.add(ServerAuthentication.YES); } private static final Set principalConstraints = new HashSet(); static { principalConstraints.add(ClientMaxPrincipal.class); principalConstraints.add(ClientMaxPrincipalType.class); principalConstraints.add(ClientMinPrincipal.class); principalConstraints.add(ClientMinPrincipalType.class); principalConstraints.add(ServerMinPrincipal.class); } private final InvocationConstraints distilled; private X500Constraints(InvocationConstraints distilled) { this.distilled = distilled; } /** * Returns X500Constraints instance representing the processed constraints. * If request is true, the constraints apply to multicast requests; * otherwise, they apply to a multicast announcements. Throws an * UnsupportedConstraintException if the constraints are unfulfillable * (note that a successful return does not imply that the constraints are * necessarily fulfillable). */ static X500Constraints process(InvocationConstraints constraints, boolean request) throws UnsupportedConstraintException { if (constraints == null) { constraints = InvocationConstraints.EMPTY; } return new X500Constraints(new InvocationConstraints( distill(constraints.requirements(), request, true), distill(constraints.preferences(), request, false))); } /** * Checks the given client principal against the constraints represented by * this instance, returning the number of preferences satisfied, or -1 if * the constraint requirements are not satisfied by the principal. */ int checkClientPrincipal(X500Principal principal) { for (Iterator i = distilled.requirements().iterator(); i.hasNext(); ) { if (!clientPrincipalSatisfies( principal, (InvocationConstraint) i.next())) { return -1; } } int satisfied = 0; for (Iterator i = distilled.preferences().iterator(); i.hasNext(); ) { if (clientPrincipalSatisfies( principal, (InvocationConstraint) i.next())) { satisfied++; } } return satisfied; } /** * Checks the given server principal against the constraints represented by * this instance, returning the number of preferences satisfied, or -1 if * the constraint requirements are not satisfied by the principal. */ int checkServerPrincipal(X500Principal principal) { for (Iterator i = distilled.requirements().iterator(); i.hasNext(); ) { if (!serverPrincipalSatisfies( principal, (InvocationConstraint) i.next())) { return -1; } } int satisfied = 0; for (Iterator i = distilled.preferences().iterator(); i.hasNext(); ) { if (serverPrincipalSatisfies( principal, (InvocationConstraint) i.next())) { satisfied++; } } return satisfied; } /** * Returns principal-dependent constraints distilled from the given set of * overall constraints. If request is true, the given constraints apply to * multicast requests; otherwise, they apply to multicast announcements. * If required is true, then an UnsupportedConstraintException is thrown if * an unsupported constraint is encountered; otherwise, unsupported * constraints are ignored. */ private static Collection distill(Set constraints, boolean request, boolean required) throws UnsupportedConstraintException { Collection dist = new ArrayList(); for (Iterator i = constraints.iterator(); i.hasNext(); ) { InvocationConstraint c = (InvocationConstraint) i.next(); Object d = distill(c, request); if (d instanceof InvocationConstraint) { dist.add(d); } else if (required && d == UNSUPPORTED) { throw new UnsupportedConstraintException("unsupported: " + c); } } return dist; } /** * Returns distilled (principal-dependent) constraint, or * SUPPORTED/UNSUPPORTED if the constraint is unconditionally supported or * not supported. If request is true, the given constraint applies to * multicast requests; otherwise, it applies to multicast announcements. */ private static Object distill(InvocationConstraint constraint, boolean request) { Class cl = constraint.getClass(); Set supported = request ? supportedRequestConstraints : supportedAnnouncementConstraints; if (supported.contains(constraint) || supported.contains(cl)) { return SUPPORTED; } if (principalConstraints.contains(cl)) { return constraint; } if (constraint instanceof ConstraintAlternatives) { ConstraintAlternatives ca = (ConstraintAlternatives) constraint; Collection dist = new ArrayList(); for (Iterator i = ca.elements().iterator(); i.hasNext(); ) { Object d = distill((InvocationConstraint) i.next(), request); if (d == SUPPORTED) { return SUPPORTED; } else if (d instanceof InvocationConstraint) { dist.add(d); } } return dist.isEmpty() ? UNSUPPORTED : ConstraintAlternatives.create(dist); } return UNSUPPORTED; } /** * Returns true if the specified client principal satisfies the given * constraint; returns false otherwise. */ private static boolean clientPrincipalSatisfies( X500Principal principal, InvocationConstraint constraint) { if (constraint instanceof ClientMaxPrincipal) { return ((ClientMaxPrincipal) constraint).elements().contains( principal); } if (constraint instanceof ClientMaxPrincipalType) { Set s = ((ClientMaxPrincipalType) constraint).elements(); for (Iterator i = s.iterator(); i.hasNext(); ) { if (((Class) i.next()).isInstance(principal)) { return true; } } return false; } if (constraint instanceof ClientMinPrincipal) { Set s = ((ClientMinPrincipal) constraint).elements(); return s.size() == 1 && s.contains(principal); } if (constraint instanceof ClientMinPrincipalType) { Set s = ((ClientMinPrincipalType) constraint).elements(); for (Iterator i = s.iterator(); i.hasNext(); ) { if (!((Class) i.next()).isInstance(principal)) { return false; } } return true; } if (constraint instanceof ConstraintAlternatives) { Set s = ((ConstraintAlternatives) constraint).elements(); for (Iterator i = s.iterator(); i.hasNext(); ) { if (clientPrincipalSatisfies( principal, (InvocationConstraint) i.next())) { return true; } } return false; } /* * Server principal constraints vacuously satisfied, since distilling * constraints with request == true would have rejected * ServerAuthentication.YES. */ return true; } /** * Returns true if the specified server principal satisfies the given * constraint; returns false otherwise. */ private static boolean serverPrincipalSatisfies( X500Principal principal, InvocationConstraint constraint) { if (constraint instanceof ServerMinPrincipal) { Set s = ((ServerMinPrincipal) constraint).elements(); return s.size() == 1 && s.contains(principal); } if (constraint instanceof ConstraintAlternatives) { Set s = ((ConstraintAlternatives) constraint).elements(); for (Iterator i = s.iterator(); i.hasNext(); ) { if (serverPrincipalSatisfies( principal, (InvocationConstraint) i.next())) { return true; } } return false; } /* * Client principal constraints vacuously satisfied, since distilling * constraints with request == false would have rejected * ClientAuthentication.YES. */ return true; } }