I struggled today to add a simple url-pattern security-policy on Weblogic using WLST(Web-Logic-Scripting-Tool). A google-search not revealing much is a rarity these days, so I decided to research and blog my findings here. I hope it help others, and it sure will help me as I am going to forget about it in a couple months, especially with a long vacation around the corner.
The problem I was trying to solve is simple: I wanted to enforce HTTP Basic authentication on an URI, using a url-pattern security-policy, and be able to configure this security using WLST. Ultimately, an example URL like http://host:port/myapp/someresource/* will have a restricted access.
This is fairly easy using the Weblogic admin-console, and below are typical high-level steps. We will simplify this further by excluding roles, groups and grant access only to a single-user.
1. Deploy application with CustomRolesAndSecurity as a security-model.
2. Add a user in default security-realm
3. Add url-pattern security-policy, and then add policy-condition to allow access to only #2 user.
Simple. But now how do we do the same using WLST? The #1 and #2 steps above using WLST are well-documented elsewhere, and the jython snippet in-brief here:
Application Deployment: myapp.war
deploy('myapp','/tmp/myapp.war',securityModel='CustomRolesAndPolicies') |
Adding user: UserId=>testuser, Password=>testpass12
securityRealm=cmo.getSecurityConfiguration().getDefaultRealm()
authenticationProvider=securityRealm.lookupAuthenticationProvider('DefaultAuthenticator')
authenticationProvider.createUser('testuser','testpass12','comment about user') |
Now the real topic of the blog-post - how to add the security-policy using WLST? There is a weblogic MBean called XACMLAuthorizerMBeanImpl and it has two methods to create/add a security-policy for a resource.
1. createPolicy(String resourceId, String expression)
A challenge in using above method is to compose the
resourceId and the
expression. There are different types of resources which could be protected such as uri, ejb, jms,webservice etc, and policies for all can be created using the same method. The resourceId however has to be resource-type specific, with patterns and stuff encoded, so care need to be taken to generate an appropriate string. To that, Resource classes in weblogic.security.service package could be used.
import weblogic.security.service.URLResource
#r=weblogic.security.service.URLResource(application,context_path,pattern,httpMethod,transport)
r=weblogic.security.service.URLResource('myapp','/myapp','/somepath/*',None,None)
resourceID=r.toString() |
The resourceID value we get from above is:
type=<url>, application=myapp, contextPath=/myapp, uri=/somepath/*.
Next, we need the expression and that is bit of a challenge too, but for a simple case of only one user it is
Usr(testuser) without any logical-operators or so.
expression='Usr('+'testuser'+')' |
With resourceID and expression available, now simply get the authorizer MBean and call createPolicy() operation, as follows:
authorizer=securityRealm.lookupAuthorizer('XACMLAuthorizer')
authorizer.createPolicy(resourceID,expression) |
2. addPolicy(String policy)
This second method of creating a policy needs access policy defined in a XACML document. Here is a jython snippet that uses a sample XACML to create a policy using addPolicy() method. I chose TQS of jython to compose the long XACML for the above URL pattern.
<Policy PolicyId="urn:bea:xacml:2.0:entitlement:resource:type@E@Furl@G@M@Oapplication@Emyapp@M@OcontextPath@E@Umyapp@M@Ouri@E@UTest2@U@K" RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable">
<Description>Usr(testuser)</Description>
<ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">type=<url>, application=myapp, contextPath=/myapp, uri=/somepath/*</AttributeValue>
<ResourceAttributeDesignator AttributeId="urn:oasis:names:tc:xacml:2.0:resource:resource-ancestor-or-self" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"/>
<Rule RuleId="primary-rule" Effect="Permit">
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-is-in">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">testuser</AttributeValue>
<SubjectAttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" DataType="http://www.w3.org/2001/XMLSchema#string"/>
<Rule RuleId="deny-rule" Effect="Deny"></Rule>
authorizer=securityRealm.lookupAuthorizer('XACMLAuthorizer')
authorizer.addPolicy(policy)
|
Now some questions:
1. How do I get XACML for a possibly complex policy?
One idea would be create the complex security-policy through admin-console, and then export the security-realm(security-realm-->migration-->export). It creates a bunch of files in a specified directory, and one file in there of interest is the XACMLAuthorizer.dat.
The XACMLAuthorizer.dat, despite the extension, is a valid XML document and contains the whole set of policies. Now search for the policy that you created through the admin-console and grab that complete "Policy" element, and that is the XACML document you need using WLST/addPolicy() method.
2. With regard to createPolicy() method, I can create a resourceID using appropriate class for a resource from the weblogic.security.service package. However, how do I create a complex expression if there are multiple policy-conditions?
One approach would be to add policy-conditions through the admin-console. And then simply query the Expression attribute as follows for use in WLST.
import weblogic.security.service.URLResource
r=weblogic.security.service.URLResource('myapp','/myapp','/someresource/*',None,None)
resourceID=r.toString()
securityRealm=cmo.getSecurityConfiguration().getDefaultRealm()
authorizer=securityRealm.lookupAuthorizer('XACMLAuthorizer')
import java.util.Properties
p=authorizer.getPolicy(resourceID)
Expression=p.get('Expression')
print Expression
|