001/**
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003 *
004 * Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
005 *
006 * The contents of this file are subject to the terms
007 * of the Common Development and Distribution License
008 * (the License). You may not use this file except in
009 * compliance with the License.
010 *
011 * You can obtain a copy of the License at
012 * https://opensso.dev.java.net/public/CDDLv1.0.html or
013 * opensso/legal/CDDLv1.0.txt
014 * See the License for the specific language governing
015 * permission and limitations under the License.
016 *
017 * When distributing Covered Code, include this CDDL
018 * Header Notice in each file and include the License file
019 * at opensso/legal/CDDLv1.0.txt.
020 * If applicable, add the following below the CDDL Header,
021 * with the fields enclosed by brackets [] replaced by
022 * your own identifying information:
023 * "Portions Copyrighted [year] [name of copyright owner]"
024 *
025 * $Id: ISPermission.java,v 1.5 2008/08/19 19:09:17 veiming Exp $
026 *
027 */
028
029package com.sun.identity.policy.jaas;
030
031import com.iplanet.sso.SSOToken;
032import com.iplanet.sso.SSOTokenManager;
033import com.iplanet.sso.SSOException;
034
035import com.sun.identity.authentication.service.SSOTokenPrincipal;
036import com.sun.identity.policy.client.PolicyEvaluator;
037import com.sun.identity.policy.client.PolicyEvaluatorFactory;
038import com.sun.identity.shared.debug.Debug;
039
040import java.security.Permission;
041import java.security.CodeSource;
042import java.security.ProtectionDomain;
043import java.security.PermissionCollection;
044
045import javax.security.auth.Subject;
046import java.security.Principal;
047
048import java.util.Set;
049import java.util.HashSet;
050import java.util.StringTokenizer;
051import java.util.Map;
052import java.util.Collections;
053
054/**
055 * This class provides the support for JAAS Authorization service 
056 * Its a new JAAS <code>Permission</code> which extends the
057 * {@link java.security.Permission} class. This is the only
058 * API which gets used by an application/container to evaluate policy against
059 * the OpenSSO Policy framework. This class provides implementations
060 * of all the required abstract methods of <code>java.security.Permission</code>
061 * , in a way that the policy evaluation is made against the OpenSSO
062 * Enterprise's Policy service.
063 * <p>
064 * For example, one would use this class as follows to evaluate policy
065 * permissions:
066 * <pre>
067 * ISPermission perm = new ISPermission("iPlanetAMWebAgentService",
068 *                  "http://www.sun.com:80","GET");
069 * AccessController.checkPermission(perm);
070 * </pre>
071 * If OpenSSO has the policy service
072 * <code>iPlanetAMWebAgentService</code> which has a <code>Rule</code> defined
073 * for resource <code>http://www.sun.com:80</code>
074 * with action "GET" with allow privilege, this call will return quietly, if
075 * such a policy is not found then access is denied and Exception thrown
076 * accordingly. Also <code>ISPermission</code> co-exists with the 
077 * permissions specified in the JDK policy store ( by default file <code>
078 * sun.security.provider.PolicyFile</code> or defined on the command line 
079 * using the -D option.
080 *
081 * <p>
082 * @see java.security.Permission
083 * @see javax.security.auth.Subject
084 * @see java.security.ProtectionDomain
085 * <p>
086 *
087 * @supported.all.api
088 */
089public class ISPermission extends Permission {
090    private Subject subject;
091    private CodeSource codesource;
092    private ProtectionDomain protectionDomain;
093    private String serviceName;
094    private String resourceName;
095    private String actions;
096    private Set actionSet;
097    private Map envParams = Collections.synchronizedMap(Collections.EMPTY_MAP);
098    private PolicyEvaluatorFactory policyEvalFactory;
099    static Debug debug = Debug.getInstance("amPolicy");
100
101    /**
102     * Constructs an <code>ISPermission</code> instance, with the specified
103     * <code>ProtectionDomain</code>.
104     *
105     * @param pd <code>ProtectionDomain</code> for which this
106     *        <code>ISPermission</code> is being created.
107     */
108    protected ISPermission(ProtectionDomain pd) {
109        super("ISPermission"); 
110        if (debug.messageEnabled()) {
111            debug.message("ISPermission(protectionDomain) constructor "
112                + "called ");
113        }
114        this.protectionDomain = pd;
115    }
116
117    /**
118     * Constructs an <code>ISPermission</code> instance, with the specified
119     * <code>Subject</code> and the <code>CodeSource</code>.
120     *
121     * @param subject <code>Subject</code> for which this
122     *        <code>ISPermission</code> is being created.
123     * @param codesource <code>CodeSource</code> for which this permission is
124     *        being created.
125     */
126    public ISPermission(Subject subject,CodeSource codesource) {
127        super("ISPermission"); 
128        if (debug.messageEnabled()) {
129            debug.message("ISPermission(subject,codesource) constructor "
130                + "called ");
131        }
132        this.subject = subject;
133        this.codesource = codesource;
134    }
135
136    /**
137     * Constructs an <code>ISPermission</code> instance, with the specified
138     * <code>CodeSource</code>.
139     *
140     * @param codesource <code>CodeSource</code> for which this permission is
141     *        being created.
142     */
143    public ISPermission(CodeSource codesource) {
144        super("ISPermission"); 
145        if (debug.messageEnabled()) {
146            debug.message("ISPermission(codesource) constructor "
147                + "called ");
148        }
149        this.codesource = codesource;
150    }
151
152    /**
153     * Constructs an <code>ISPermission</code> instance, with the specified
154     * service name, resource name and action name.
155     * @param serviceName name of service for which this
156     *        <code>ISPermission</code> is being created. This name needs to be
157     *        one of the loaded services in the OpenSSO's policy
158     *        engine. example: <code>iPlanetAMWegAgentService</code>
159     *
160     * @param resourceName name of the resource for which this 
161     *        <code>ISPermission</code> is being defined.
162     *
163     * @param actions name of the action that needs to be checked for. It
164     *        may be a <code>String</code> like "GET", "POST" in case of 
165     *        service name <code>iPlanetAMWebAgentService</code>.
166     */
167    public ISPermission(String serviceName,String resourceName, String 
168        actions) 
169    {
170        super("ISPermission");
171        this.serviceName = serviceName;
172        this.resourceName = resourceName;
173        this.actions = actions;
174        debug.message("ISPermission:: Constructor called");
175    }
176
177
178    /**
179     * Constructs an <code>ISPermission</code> instance, with the specified
180     * service name, resource name and action name.
181     * @param serviceName name of service for which this
182     *        <code>ISPermission</code> is being created. This name needs to be
183     *        one of the loaded policy services in the OpenSSO.
184     *        example:
185     *        <code>iPlanetAMWegAgentService</code>
186     *
187     * @param resourceName name of the resource for which this 
188     *        <code>ISPermission</code> is being defined.
189     *
190     * @param actions name of the action that needs to be checked for. It
191     *        may be a <code>String</code> like "GET", "POST" in case of 
192     *        service name <code>iPlanetAMWebAgentService</code>.
193     * @param envParams a <code>java.util.Map</code> of environment parameters
194     *        which are used by the  
195     *        <code>com.sun.identity.policy.client.PolicyEvaluator</code> 
196     *        to evaluate the <code>com.sun.identity.policy.Conditions</code> 
197     *        associated with the policy. This is a Map of attribute-value pairs
198     *        representing the environment under which the policy needs to be
199     *        evaluated.
200     */
201    public ISPermission(String serviceName,String resourceName, 
202        String actions, Map envParams) 
203    {
204        super("ISPermission");
205        this.serviceName = serviceName;
206        this.resourceName = resourceName;
207        this.actions = actions;
208        this.envParams = envParams;
209        debug.message("ISPermission:: Constructor called");
210    }
211
212    /**
213     * returns the name of the service associated with this <code>ISPermission
214     * </code>.
215     * @return <code>String</code> representing the name of the service for this
216     *         permission.
217     */
218    public String getServiceName() {
219        debug.message("ISPermission: getServiceName called");
220        return serviceName;
221    }
222
223    /**
224     * returns the name of the resource associated with this <code>ISPermission
225     * </code>.
226     * @return  <code>String</code> representing the name of the resource for 
227     *          this permission.
228     */
229    public String getResourceName() {
230        debug.message("ISPermission: getResourceName called");
231        return resourceName;
232    }
233
234    /**
235     * returns environment parameters and their values associated with this 
236     * <code>ISPermission</code>.
237     * @return  <code>Map</code> representing the environment parameters of
238     *          this permission. The <code>Map</code> consists of attribute 
239     *          value pairs.
240     */
241    public Map getEnvParams() {
242        return envParams;
243    }
244
245    /**
246     * returns a comma separated list of actions associated with this 
247     * <code>ISPermission</code>.
248     * @return  a comma separated <code>String</code> representing the name 
249     *          of the action for this object. For example for:
250     *          <pre>
251     *          ISPermission isp = new ISPermission("iPlanetAMWebAgentService, 
252     *              "http://www.sun.com:80", "GET, POST");
253     *          getActions() would return "GET,POST"
254     *          </pre>
255     */
256    public String getActions() {
257        debug.message("ISPermission: getActions called");
258        if (debug.messageEnabled()) {
259            debug.message("returning actions:"+actions);
260        }
261        return actions;
262    }
263
264    /**
265     * Returns true if two comma separated strings are equal.
266     *
267     * @param actions1 actions string.
268     * @param actions2 actions string.
269     * @return true if two comma separated strings are equal.
270     */
271    private boolean actionEquals(String actions1, String actions2) {
272            Set actionSet1 = Collections.synchronizedSet(new HashSet());
273            Set actionSet2 = Collections.synchronizedSet(new HashSet());
274        if (actions1 != null) {
275               StringTokenizer st = new StringTokenizer(actions1,",");
276            while (st.hasMoreTokens()) {
277                String action = (String)st.nextToken().trim();
278                actionSet1.add(action);
279            }
280        }
281        if (actions2 != null) {
282               StringTokenizer st = new StringTokenizer(actions2,",");
283            while (st.hasMoreTokens()) {
284                String action = (String)st.nextToken().trim();
285                actionSet2.add(action);
286            }
287        }
288        return actionSet1.equals(actionSet2);
289    }
290
291    /**
292     * Returns a <code>Set</code> of actions for this Permission.
293     * @param actions comma separated actions string.
294     * @return set of actions in this permsision.
295     *
296     */
297    private Set actionsInSet(String actions) {
298        if (actionSet == null) {
299                actionSet = Collections.synchronizedSet(new HashSet());
300        } else {
301            return actionSet;
302        }
303        if (actions != null) {
304               StringTokenizer st = new StringTokenizer(actions,",");
305            while (st.hasMoreTokens()) {
306                String action = (String)st.nextToken();
307                actionSet.add(action);
308            }
309        }
310        return actionSet;
311    }
312        
313    /**
314     * returns the <code>Subject</code>associated with this <code>ISPermission
315     * </code>.
316     * @return  <code>javax.security.auth.Subject</code> representing the 
317     *          subject of this permission.
318     */
319    public Subject getSubject() {
320        debug.message("ISPermission:: getSubject called ");
321        return subject;
322    }
323
324    /**
325     * returns the <code>CodeSource</code>associated with this 
326     * <code>ISPermission</code>.
327     * @return <code>java.security.CodeSource</code> representing the 
328     *         <code>codesource</code> of this permission. 
329     */
330    public CodeSource getCodeSource() {
331        debug.message("ISPermission:: getCodeSource called ");
332        return codesource;
333    }
334
335    /**
336     * returns the <code>ProtectionDomain</code>associated with this 
337     * <code>ISPermission</code>.
338     * @return <code>java.security.ProtectionDomain</code> representing the 
339     *         <code>protectionDomain</code> of this permission. 
340     */
341    public ProtectionDomain getProtectionDomain() {
342        debug.message("ISPermission:: getProtectionDomain called ");
343        return protectionDomain;
344    }
345
346    /**
347     * Returns true if two <code>ISPermission</code> objects for equality.
348     *
349     * @param obj <code>ISPermission</code> object.
350     * @return true if subject, <code>codesource</code>, service name, resource
351     *         name actions and environment parameters of both objects are 
352     *         equal.
353     */
354    public boolean equals(Object obj){
355        boolean result = true;
356        debug.message("ISPermission:: equals(Object) called ");
357        if (obj == this) {
358            if (debug.messageEnabled()) {
359                debug.message("ISPermission::equals::this " +result);
360            }
361            return true;
362        }
363        if (obj instanceof ISPermission) {
364            ISPermission perm = (ISPermission) obj;
365            Subject subject = perm.getSubject();
366            if (subject != null) {
367                result = subject.equals(this.subject);
368            } else {
369                if (this.subject != null) {
370                    result = false; // subject is null, while this.subject is 
371                                    // not null.
372                }
373            }
374            if (debug.messageEnabled()) {
375                debug.message("ISPermission::subject equals:"+result);
376            }
377            if (result) {
378                CodeSource codesource = perm.getCodeSource();
379                if (codesource != null) {
380                    result = codesource.equals(this.codesource);
381                    if (debug.messageEnabled()) {
382                          debug.message("ISPermission::codesource equals:"+
383                            codesource.equals(this.codesource));
384                    }
385                } else {
386                    if (this.codesource != null) {
387                        result = false;
388                    }
389                }
390            }
391            if (result) {
392                ProtectionDomain protectionDomain = perm.getProtectionDomain();
393                if (protectionDomain != null) {
394                    result = protectionDomain.equals(this.protectionDomain);
395                    if (debug.messageEnabled()) {
396                          debug.message("ISPermission::protectionDomain equals:"
397                            + protectionDomain.equals(this.protectionDomain));
398                    }
399                } else {
400                    if (this.protectionDomain != null) {
401                        result = false;
402                    }
403                }
404            }
405            if (result) {
406                String serviceName = perm.getServiceName();
407                if (serviceName != null) {
408                    result = serviceName.equals(this.serviceName); 
409                    if (debug.messageEnabled()) {
410                          debug.message("ISPermission::servicename equals:"+
411                            serviceName.equals(this.serviceName));
412                    }
413                } else {
414                    if (this.serviceName != null) {
415                        result = false;
416                    }
417                }
418            }
419            if (result) {
420                String resourceName = perm.getResourceName();
421               if (resourceName != null) {
422                   result = resourceName.equals(this.resourceName);
423                    if (debug.messageEnabled()) {
424                          debug.message("ISPermission::resourceName equals:"+
425                            resourceName.equals(this.resourceName));
426                    }
427                } else {
428                    if (this.resourceName != null) {
429                        result = false;
430                    }
431                }
432            }
433            if (result) {
434                String actions = perm.getActions();
435                if (actions != null) {
436                    result = actionEquals(actions,this.actions);
437                    if (debug.messageEnabled()) {
438                          debug.message("ISPermission::Actions equals:"+
439                            actionEquals(actions,this.actions));
440                    }
441                } else {
442                    if (this.actions != null) {
443                        result = false;
444                    }
445                }
446            }
447            if (result) {
448                Map envParams = perm.getEnvParams();
449                if (envParams != null  && !envParams.isEmpty())  {
450                    result = envParams.equals(this.envParams);
451                    if (debug.messageEnabled()) {
452                        debug.message("ISPermission::equals::envMap"
453                            + envParams.equals(this.envParams));
454                    }
455                } else {
456                    if (this.envParams != null && !this.envParams.isEmpty()) {
457                        result = false;
458                    }
459                }
460            }
461        }
462        if (debug.messageEnabled()) {
463            debug.message("ISPermission::equals::returning " +result);
464        }
465        return result;
466    }
467
468    /**
469     * Returns the hash code value for this Permission object.
470     * <P>
471     * The required <code>hashCode</code> behavior for Permission Objects is
472     * the following: <p>
473     * <ul>
474     * <li>Whenever it is invoked on the same Permission object more than 
475     *     once during an execution of a Java application, the 
476     *     <code>hashCode</code> method
477     *     must consistently return the same integer. This integer need not 
478     *     remain consistent from one execution of an application to another 
479     *     execution of the same application. <p>
480     * <li>If two Permission objects are equal according to the 
481     *     <code>equals</code> 
482     *     method, then calling the <code>hashCode</code> method on each of the
483     *     two Permission objects must produce the same integer result. 
484     * </ul>
485     *
486     * @return a hash code value for this object.
487     */
488    public int hashCode() {
489        int hash = 0;
490        if (subject != null) {
491            hash = hash + this.subject.hashCode();
492        }
493        if (codesource != null) {
494            hash = hash + this.codesource.hashCode();
495        }
496        if (protectionDomain != null) {
497            hash = hash + this.protectionDomain.hashCode();
498        }
499        if (serviceName != null) {
500            hash = hash + this.serviceName.hashCode();
501        }
502        if (resourceName != null) {
503            hash = hash + this.resourceName.hashCode();
504        }
505        if (actions != null) {
506            Set actionSet = actionsInSet(actions);
507            hash = hash + actionSet.hashCode();
508        }
509        if (envParams != null) {
510            hash = hash + this.envParams.hashCode();
511        }
512        if (debug.messageEnabled()) {
513            debug.message("ISPermission::hashCode::"+hash);
514        }
515        return hash;
516    }
517
518    /**
519     * Checks if the specified permission's actions are "implied by" 
520     * this object's actions.
521     * <P>
522     * The <code>implies</code> method is used by the
523     * <code>AccessController</code> to determine whether or not a requested
524     * permission is implied by another permission that is known to be valid
525     * in the current execution context.
526     *
527     * @param perm the permission to check against.
528     *
529     * @return true if the specified permission is implied by this object,
530     *         false if not. The check is made against the OpenSSO's 
531     *         policy service to determine this evaluation.
532     */
533    public boolean implies(Permission perm) {
534        debug.message("ISPermission: implies called");
535        boolean allowed = false;
536        if (perm instanceof ISPermission) {
537            debug.message("ISPermission:passed perm is of type ISPermission");
538            if (protectionDomain != null) {
539                debug.message("ISPermission:implies:protectionDomain not null");
540                if (debug.messageEnabled()) {
541                    debug.message("ISPermission::implies: protectionDomain:"
542                    +protectionDomain.toString());
543                }
544                final String serviceName =((ISPermission)perm).getServiceName();
545                final String resourceName =
546                    ((ISPermission)perm).getResourceName();
547                final String actions = ((ISPermission)perm).getActions();
548                final Map envParams = ((ISPermission)perm).getEnvParams();
549                if (debug.messageEnabled()) {
550                    debug.message("ISPermission: resourceName="
551                        +resourceName);
552                    debug.message("ISPermission: serviceName="
553                        +serviceName);
554                    debug.message("ISPermission: actions="+actions);
555                }
556                SSOTokenPrincipal tokenPrincipal = null;
557                try {
558                    Principal[] principals = protectionDomain.getPrincipals();
559                    // principals should have only one entry
560                    Principal principal = (Principal)principals[0];
561                    if (principal.getName().equals("com.sun.identity."
562                        +"authentication.service.SSOTokenPrincipal")) {
563                        if (debug.messageEnabled()) {
564                            debug.message("ISPermission::implies:principals:"
565                                +principal.toString());
566                        }
567                        tokenPrincipal = (SSOTokenPrincipal) principal;
568                    }
569                    if (tokenPrincipal == null) {
570                        if (debug.messageEnabled()) {
571                            debug.error("ISPermission::implies:"
572                                + " Principal is null");
573                        }
574                    } else {
575                        SSOTokenManager ssomgr = SSOTokenManager.getInstance();
576                        final SSOToken token =
577                            ssomgr.createSSOToken(tokenPrincipal.getName());
578                        /* TODO currently ISPermission uses remote policy 
579                        client API so if this class gets used from server side
580                        , will always make remote call, need to make changes 
581                        in this code to to make a local/remote call accordingly.
582                        */
583                            if (policyEvalFactory == null) { 
584                             policyEvalFactory = 
585                                PolicyEvaluatorFactory.getInstance(); 
586                            } 
587                            PolicyEvaluator policyEvaluator = 
588                        policyEvalFactory.
589                            getPolicyEvaluator(serviceName);
590                        if (debug.messageEnabled()) {
591                            debug.message("ISPermission::implies::created "
592                                + "PolicyEvaluator for "+serviceName);
593                        }
594                        if (actions != null) {
595                                   StringTokenizer st = 
596                                new StringTokenizer(actions,",");
597                                while (st.hasMoreTokens()) {
598                                String action = (String)st.nextToken();
599                                allowed  =  policyEvaluator.isAllowed(token, 
600                                    resourceName , action ,envParams);
601                                    if (!allowed) {
602                                    break; // the final result is not allowwed
603                                }
604                                if (debug.messageEnabled()) {
605                                    debug.message("ISPermission::result for "
606                                        + action+" is :"+allowed);
607                                }
608                            }
609                            if (debug.messageEnabled()) {
610                                debug.message("ISPermission::result for "
611                                    + actions+" is :"+allowed);
612                            }
613                        } else {
614                            if (debug.messageEnabled()) {
615                                debug.message("ISPermission:: actions is null");
616                            }
617                        }
618                    }
619                } catch (SSOException ssoe ) {
620                    if (debug.messageEnabled()) {
621                        debug.error("ISPermission::SSOException:"
622                            +ssoe.getMessage());
623                        ssoe.printStackTrace();
624                    }
625                } catch (Exception  e ) {
626                    if (debug.messageEnabled()) {
627                        debug.error("ISPermission::Exception:"
628                            +e.getMessage());
629                        e.printStackTrace();
630                    }
631                }
632            } else {
633                debug.message("ISPermission:: subject was null");
634            }
635        }
636        if (debug.messageEnabled()) {
637            debug.message("ISPermission: allowed::"+allowed);
638        }
639        return allowed;
640    }
641
642    /**
643     * Returns a <code>java.security.PermissionCollection</code> to store this 
644     * kind of Permission.
645     *
646     * @return an instance of <code>ISPermissionCollection</code>
647     */
648    public PermissionCollection newPermissionCollection() {
649        debug.message("ISPermission:: newISPermissionCollection() called");
650        return new ISPermissionCollection();
651    }
652
653
654    /**
655     * Returns a string describing this Permission. 
656     * @return <code>String</code> containing information about this Permission.
657     */
658    public String toString() {
659        StringBuffer str = new StringBuffer(200);
660        str = str.append("(").append(getClass().getName()).append("\n");
661        String actions = getActions();
662        if (subject != null) {
663            str = str.append(subject.toString()).append("\n");
664        }
665        if (codesource != null) {
666            str = str.append(codesource.toString()).append("\n");
667        }
668        if ((serviceName != null) && (serviceName.length() != 0)) { 
669            str = str.append("serviceName=").append(serviceName).append("\n");
670        }
671        if ((resourceName != null) && (resourceName.length() != 0)) { 
672            str = str.append("resourceName=").append(resourceName).append("\n");
673        }
674        if ((actions != null) && (actions.length() != 0)) { 
675            str = str.append("actions=").append(actions).append("\n");
676        }
677        if ((envParams != null) && !(envParams.isEmpty())) { 
678            str = str.append("envParams=").append(envParams.values())
679                     .append("\n");
680        }
681        str.append(")");
682        return str.toString();
683    }
684}




























































Copyright © 2010-2017, ForgeRock All Rights Reserved.