Blog from your iPhone / iPod
Manage your EC2 instances from your iPhone / iPod
Only weekness was - the way it accepts credentials - one way it's more convenient - but in other, you have to pass your credentias over the network in cleartext - and the app will store those internally.
Google Caffaine
Adding DZone to iPhone / iPod Touch
Failing to find one - I followed the following work-around - which worked perfectly for me - so, thought of sharng it for the benefit of others.
1. Open up Safari and go to http://www.dzone.com
2. Add a bookmark to it - and set the Title of the bookmark as - 'Submit to DZone'
3. Now - tap on the Bookmarks link, as in the image shown below - click 'Edit' and select 'Submit to DZone'.
4. Remove the current Address of the 'Submit to DZone' bookmark and set the following..
javascript:window.loaction='http://www.dzone.com/links/add.html?url='+escape(window.location)+'&title='+escape(document.title)+'&description='+escape(document.title)5. Now - go to any web site you want - and to submit that link to DZone - just tap on the Bookmarks link on the bottom of the browser and select 'Submit to DZone'.
First look at Google Chrome OS
To run this - we need to have VMWare Workstation - a 7 days trial version availbale from here to download.
Now - you need to wait hours and hours to get the trial version license key from VMWare. Instead of that use this - M142T-1034J-M8280-0KA8H-A49PC. If you are curious about this - here is the news behind that.
All set - setup your image with the VMWare Workstaion - steps here.
That's it - now you can login with your GMail account to your OS :)
Not bad at all - how about using an OpenID instead...
Read this for more info - "11 Things You Need to Know About Google's Chrome OS".
http://RampartFAQ.COM
Basics
1.What is Rampart?
2.How to configure Rampart in Axis2?
3.How to run Rampart samples with Apache Tomcat?
4.How to enable SSL on Tomcat?
5.How does the nonce and the timestamp get generated for hashed passwords in UsernameToken?
6.How to create wildcard certificates with java keytool?
7.How to import/export certificates using Java keytool?
Intermediate
1.How to use Axis2 Dynamic Client to invoke Secured Web Services?
2.How password Callback Handlers work in Rampart?
3.How to ask for a hashed password in security policy?
4.How identity delegation works with ActAs in WS-Trust 1.4?
5.How SOAP message encryption works?
6.What is Assymetric Binding?
7.Would timestamp validation fail when servers and clients running in different timezones?
8.How to secure a web service with UsernameToken + HTTPS?
9.How to enable SSL on WAMP?
10.How to dump out JKS private key?
11.How to create a Certificate Authority with OpenSSL on Windows?
12.How to secure web services with HTTP Basic Authentication?
13.How to do UsernameToken authentication for web services based on AD?
14.How to secure a web service with UsernameToken?
15.Can we have multiple private keys in a single JKS?
16.<ramp:user> vs <ramp:encryptionUser> vs <ramp:userCertAlias>
Advance
1.How to call web services having SSL mutual authentication enabled?
2.How to setup a secure conversation with an STS?
3.How to ceate a new JKS with an existing private key and a signed certificate?
4.Can we have per service, policy based results validators?
5.How to apply policies at binding hierarchy?
6.Can we avoid duplicating crypto info added to RampartConfig in different services.xml files?
7.How to enable NTLM authentication in Axis2 client?
8.What are the Rampart handlers in inflow and what do they do?
9.How to do proxy authenticaion at runtime - in Axis2 client or stub?
10.What are policy subjects and where goes security policy assertions?
11.How Token referencing works in WS-Security?
12.How to add a secured and a non secured end point to the same service?
13.How to enable security for JAX-WS services with Axis2/Rampart?
14.How to generate a non-secured response to a secured request?
Common Errors
1.org.apache.axis2.AxisFault: First Element must contain the local name, Envelope , but found html
2.java.security.UnrecoverableKeyException: Cannot recover key
3.org.apache.ws.security.WSSecurityException: An unsupported signature or encryption algorithm was used
4.[ERROR] Referenced security token could not be retrieved (Reference "#CertId-238146")
5.java.security.NoSuchAlgorithmException: Cannot find any provider supporting RSA/NONE/OAEPPADDING
6.org.apache.axis2.phaseresolver.PhaseException: Did not find the desired phase 'Security' while deploying handler 'PolicyBasedSecurityOutHandler'
7.java.security.InvalidKeyException: Illegal key size or default parameters
8.org.apache.rampart.RampartException: The timestamp could not be validated
Integrating Novell eDirectory with WSO2 Identity Server
Then go through this blog post which explains - how to setup an LDAP based user store with Identity Server.
You need to follow exact the same steps - except - you need to have the settings from the above image while installing Novell eDirectory - for the Identity Server LDAP configuration as shown below.
Amazon CloudFront with Blogger blogs as a Content Delivery Network
Amazon CloudFront delivers the content using a global network of edge locations. Requests for your objects are automatically routed to the nearest edge location, so content is delivered with the best possible performance.
This blog post explains how to setup Amazon CloudFront with your blog.
First you need to have an Amazon account and signed up for an S3 bucket.
This explains everything you need to know - to set that up.
Now - you have an S3 bucket - say facilelogin.
Then - we need to sign up for a CloudFront account.
Go to http://aws.amazon.com/cloudfront and sign up with the same Amazon credentials you used before.
Now - sign in to the CloudFront management console.
Click the link - Create Distribution.
Set Origin as the S3 bucket you created earlier.
Give a child domain of your blog as the CNAME [e.g. cache.facilelogin.com]
This will create a CloudFront for the set S3 bucket.
Once you highlight the distribution you created - you can see it's details on the bottom panel.
Note down following.
Domain Name : d2npqrbnybq989.cloudfront.net
CNAME : cache.facilelogin.com
Now - you need to add a CNAME record to your domain.
I got my domain from Yahoo - so to add a CNAME record there, first sign in here, and a CNAME record to your domain with,
Source : cache.facilelogin.com [Value corresponding to the Amazon distribution CNAME]
Destination : d2npqrbnybq989.cloudfront.net [Value corresponding to the Amazon distribution Domain Name]
That's it - give some time to get your CNAME updated.
Now - add whatever content you want to - the Amazon S3 bucket and refer to content from you blog as http://cache.facilelogin.com/[resource name].
The image shown in the post is loaded from the S3 bucket - managed by Amazon CloudFront.
Hands on CLOUD while legs on EARTH
1. Sign up for S3
Go to http://aws.amazon.com/s3/ and sign up for an Amazon S3 account.
Amazon S3 is storage on cloud.It provides a simple web services interface that can be used to store and retrieve any amount of data.
Read more on S3 from http://aws.amazon.com/s3/faqs/
2. Tools
Once you created the storage on cloud - there are tools which let you talk to the S3 iterface from your local computer.
CloudBerry Explorer is the one I use, it makes managing files in Amazon S3 storage EASY. By providing a user interface to Amazon S3 accounts, files, and buckets, CloudBerry lets you manage your files on cloud just as you would on your own local computer.
3. S3 with CloudBerry Explorer
Start CloudBerry Explorer --> File --> Amazon S3 Account --> New Account
Here you need to provide, an Access Key, a Secret Key and a Display. Make sure you tick the 'Use SSL' tick box.
To find your Access Key and the Secret Key - first you need to login to http://aws.amazon.com/account/ with your Amazon credentials and click on the link for 'Security Credentials'
Once you are there you can see both your Access Key ID and Secret Access Key listed under Access Keys.
Copy thoe keys from there and give those to CloudBerry Explorer.
Once you create the new account in CloudBerry Explorer - it will be listed under 'Source'.
Select your account from 'Source' - CloudBerry Explorer will talk to your S3 account and will display the buckets you created.
4. Buckets
Just like a bucket holds water, Amazon buckets are like a container for your files. You can name your buckets the way you like but it should be unique across the Amazon system.
To create a Bucket from CloudBerry - click the 'New Bucket' icon in blue on the top row.
Amazon S3 offers storage in the United States and in Europe (within the EU). You can specify where you want to store your data when you create your Amazon S3 buckets.
Keep in mind that the bucket namespace is shared by all users of the system. So the name you give needs to be unique accross the system.
Once you created the bucket - that will be displayed in the left pane of the CloudBerry Explorer.
Right click on the bucket and select 'Web URL' - that will show the web url to access your bucket [e.g. http://facilelogin.s3.amazonaws.com/]
Type that on a web browser and try to access it - you won't be.
Now you need to set the access control setting for your bucket.
Once again right click on the bucket and select ACL and then ACL Settings.
If yu want all the users to have read access to your bucket - then select 'All Users' and set 'Read' permission.
Now - try to access the link from the web browser.
To move data from your local machine to the S3 bucket in the cloud - just drag and drop the files from the right pane to the S3 bucket on the left pane.
5. Sign up for EC2
Amazon Elastic Compute Cloud (Amazon EC2) is a web service that provides resizable compute capacity in the cloud.
Just as Amazon Simple Storage Service (Amazon S3) enables storage in the cloud, Amazon EC2 enables “compute” in the cloud.
Go to http://aws.amazon.com/ec2/ and sign up for an EC2 acount. You can use same Amazon credentials you used to create the S3 accont.
Read more on EC2 from http://aws.amazon.com/ec2/faqs/
6. Amazon Management console
Now, go to htp://aws.amazon.com/console/ - select EC2 from right hand side combo box and 'Sign in to the AWS Console'.
The AWS Management Console gives you a quick, global picture of your cloud computing environment so that you can see what resources you’re operating and conveniently manage those resources
7. Starting an EC2 instance
Once you sign in to the Amazon Management console, you will see a dashboard.
To start using Amazon EC2 you will want to launch a virtual server, known as an Amazon EC2 instance.
Click on the link 'Launch Instances'.
Now - this will display a set of available AMI(Amazon Machine Image)s.
Select any AMI you want - I selected 'Basic Fedora Core 8'.
In the next screen - set the number of instances as - 1.
Select create new key pair.
Public/private key pairs allow you to securely connect to your instance after it launches. To create a key pair, enter a name and click Create & Download your Key Pair.
You will then be prompted to save the private key to your computer. Note, you only need to generate a key pair once — not each time you want to deploy an Amazon EC2 instance.
Let's also create a new security group - accept the default settings there only giving access to SSH port.
Security groups determine whether a network port is open or blocked on your instance(s).
Once you are done with all tha - you'll be back on the dashboard and under 'Instances' - you can see the instance you started now.
Click on that instance and you'll see all the details about it listed down - and copy the Public DNS value[e.g: ec2-75-101-193-101.compute-1.amazonaws.com]
Now - you have a Fedora instance running on the cloud.
Let's see how to login in to it from the local machine.
8. Putty
I am using Putty under Windows, to SSH in to my Fedora instance running on the cloud.
First we need to setup the private key with it. [Rember we download a key while launching the AMI].
Start Putty --> Session --> Set Host Name - the Public DNS of our running Fedora instance.
Go to Connection/SSH/Auth - set the private key file for authentication.
Here it requires the private key in PPK format - but what we downloaded is in PEM format.
Now we need to do a conversion - we can use puttygen for that.
Once done set the PPK file as the private key file for authentication in Putty.
Now, go to Connection/Data - set 'root' as the Auto-login user name.
Now - we are done - click on 'Open' to connect to your Fedora instance running on EC2.
9. Launching a Windows Instance
Hear we try to launch a Windows Instance and try to remote login in to it.
Before launching a Windows AMI - let's first create new Security Group.
From the main dashboard - you can select 'Security Groups' and then create a new secuirty group.
Once created - allow RDP connection for this security group - to allow windows remote login.
Now - in the same way we did before - launch a Windows AMI - but make sure you set it's security group - the one we just created with RDP connections allowed.
To get the Windows admin password to login through remote login - highlight the Windows instance from Dashboard/Instances - select Instance Actions/Windows Actions/Get Windows Admin Password.
Hashing alone is NOT a life saver
So - nobody other than you know what your actual password is.
When you create your password - your password will go through the hashing algorithm and the hashed password will be stored in the database.
When you try to login - you enter your password in clear text - then the application will calculate the hash of the entered password and will match that with the hashed password already stored in the database. If matches, you will let in.
How does this make your password safe?
Say somebody hacked in to the database.But - still he cant see your password in clear text. So - he can't login to your account. Hacker will only get access to the hashed password - but not to the password in clear text. Keep in mind - you can't never login with the hashed password. That is bacause - what ever you enter as the password will go through a hashing algorithm and that hashed value will be matched with hashed password in the database. In case if you enter the value you found from the database - which is actually the hashed password - then that will be rehashed by tha application and try to match with the hashed password from the database - which will obviously fail.
But - is this safe enough ?
The hacker who has access to your database can still replace your hashed password with a hash he caculated with a clear text known to him. Then he can login to your account with the clear text known to him - because it will be evaluated against the hash value he replaced in the database.
That is; hashing alone is never safe.
Whenever you store anything in clear text as a hashed value - you need to store it as a salted hash.
In cryptography, a salt comprises random bits that are used as one of the inputs to a key derivation function. The other input is usually a password or passphrase in clear text. Output is the 'salt' value. Now - the application will caculate the hash value of password in clear text + the salt value and store that in the database.
Application will also store the salt value - but for best security, the salt value should be kept secret, separate from the password database.
When a user enters his password for login - the application will retreive the salt value and caculate the hash over both the salt and the entered password - and will match the result with the hash value stored in the password database.
In case a hacker having access to the database replaces the user's password with a hash value of a clear text known to him - still the password verification will fail - bacause now the hash is not just caculated with the password along - it's from both the password and the salt value. In this case if the hacker wants to access user account he should be able to gain access to the database which stores hash values as well.
So - the bottom line is - hashing along is never secure - salted hashing much secure - but all that will make it's hard to break - but never stop from breaking fully.
Although you store clear text passwords as salted hashes - it's never an alternative to not to secure access to the database.
WSO2 SOA Workshop - Santa Clara, California
Most enterprises start with creating basic services and connecting them with an Enterprise Service Bus when first adopting SOA. This session will talk about the wider usage of an ESB in SOA infrastructure and the decoupling of communication layers.
SOA Security
As many businesses move ahead with SOA, security and identity management need to be made available as a service in the architecture in a consistent and reusable way across all applications. This session will focus on implementing key security standards and identity management for SOA.
Mashups and Business Process Management for SOA
This session will introduce Mashups as an enterprise integration tool and will demonstrate the various technologies in use for service compositions in SOAs. Focusing on both automated processes and looking at how BPM fits into people-based processes, this session will also examine Open Standards for BPM, how the BPMN and BPEL standards fit together.
SOA Governance
Governance is a vital part of any SOA, and has an impact on runtime as well as design-time. Some major components of SOA governance include a registry, policy, monitoring and testing procedures. This session will discuss some predefined patterns and recommendations along with service life-cycles, resource life-cycles, metadata storage, policies and validations.
SOA with C, C++, PHP and more
As C, C++ and other such languages have been around for many years, it is predominant in legacy systems. This session will explore how These languages can be used to implement and integrate systems that use SOA principles to provide great business value to enterprise applications.
SOA Enterprise Architecture Patterns
This session will provide in-depth knowledge on how to implement an SOA solution using the basic elements in an SOA infrastructure discussed in other sessions.
Deploying WSO2 Identity Server 2.0 over WebLogic
WSO2 SOA Summer School - Security in SOA : The brain friendly edition of complex security specs
As many businesses move ahead with SOA, security and identity management need to be made available as a service in the architecture in a consistent and reusable way across all applications.
During this webinar I will focus on implementing key security standards and identity management for SOA with regards to two emerging user centric identities: OpenID & Information Cards, and also XACML for fine-grained authorization.
If you are yet to register - do it today from here.
I hope you'll enjoy this session and learn Security concepts in a brain friendly manner.
SOA Summer School: Scalable SOA by Samisa
Serious business applications that demand high volumes of transactions are most often based on SOAs. Clustering technologies are critical for some of these deployments to help achieve load balancing and high availability. This session digs deep into the scaling techniques that can be used in SOA deployments that demand high throughput and high reliability.
If you are yet to register - still its's open - further details here.
Extracting SAML assertions from a proxy service and adding them back to the service behind
There - we get the SAML Assertion to the proxy service.
Here what we are going to do is - to extract SAML Assertions from the Security header of the incoming message and add those as a custom header to the message going to the actual service.
First, please download the org.wso2.carbon.identity.samples.saml.mediator-2.0.0.SNAPSHOT.jar from here.
Stop - the ESB if it's running already.
Copy the above jar to [ESB_HOME]\webapps\ROOT\WEB-INF\plugins\console.
Open [ESB_HOME]\webapps\ROOT\WEB-INF\eclipse\configuration\org.eclipse.equinox.simpleconfigurator\bundles.info and add the following entry to the end [one line].
org.wso2.carbon.identity.samples.saml.mediator,2.0.0.SNAPSHOT,file:plugins/org.wso2.carbon.identity.samples.saml.mediator-2.0.0.SNAPSHOT.jar,10,true
Start the ESB with following.
\> wso2server.bat -cleanCache
Now, you need to add the above mediator to the in sequence of your proxy service as a Class mediator.
Following is the synapase configuration for the in/out sequences of the proxy service.
You can clearly see Class/Header/Log & Send mediators are in the in-sequence and Send mediator in the out-sequence.
<syn:proxy name="test" transports="https http" startOnLoad="true" trace="disable">
<syn:target>
<syn:inSequence>
<syn:class name="org.wso2.carbon.identity.samples.saml.mediator.SAMLAttrMediator"/>
<syn:header xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" name="wsse:Security" action="remove"/>
<syn:log level="full"/>
<syn:send/>
</syn:inSequence>
<syn:outSequence>
<syn:send/>
</syn:outSequence>
</syn:target>
</syn:proxy>
Now - the question is how do we capture the SAML attributes from the actual service.
You can call the following method from any service method to get the attributes in a HashMap.
getAttributes(MessageContext.getCurrentMessageContext());
Following is the code for getAttributes() method.
Also make sure you import following packages as well.
private static final String USER_ATTRIBUTES_ELEMENT = "UserAttributes";
private static final String USER_ATTRIBUTES_NS = "http://attributes.saml.axis2.org";
private static final String ATTRIBUTE = "Attribute";
private static final String ATTRIBUTE_NS = "AttributeNamespace";
private static final String ATTRIBUTE_VALUE = "AttributeValue";
public final static String SAML10_NS = "urn:oasis:names:tc:SAML:1.0:assertion";
public final static String SAML11_NS = "http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1";
public final static String SAML20_NS = "urn:oasis:names:tc:SAML:2.0:assertion";
public MapgetAttributes(MessageContext messageContext) {
OMElement header = null;
OMElement userAttr = null;
Iteratoriterator = null;
String samlNameSpace = null;
header = messageContext.getEnvelope().getHeader();
userAttr = header.getFirstChildWithName(new QName(USER_ATTRIBUTES_NS,
USER_ATTRIBUTES_ELEMENT));
iterator = userAttr.getChildrenWithName(new QName(SAML10_NS, ATTRIBUTE));
if (iterator.hasNext()) {
samlNameSpace = SAML10_NS;
} else {
iterator = userAttr.getChildrenWithName(new QName(SAML11_NS, ATTRIBUTE));
if (iterator.hasNext()) {
samlNameSpace = SAML11_NS;
} else {
iterator = userAttr.getChildrenWithName(new QName(SAML20_NS, ATTRIBUTE));
if (iterator.hasNext()) {
samlNameSpace = SAML20_NS;
}
}
}
if (samlNameSpace == null) {
// Unsupported SAML token type;
return null;
}
Mapattributes;
attributes = new HashMap();
while (iterator.hasNext()) {
OMElement attr = iterator.next();
OMElement attrValElement = null;
String attributeName = null;
String attributeValue = null;
attributeName = attr.getAttributeValue(new QName(ATTRIBUTE_NS));
attrValElement = attr.getFirstChildWithName(new QName(samlNameSpace, ATTRIBUTE_VALUE));
attributeValue = attrValElement.getText();
attributes.put(attributeName, attributeValue);
}
return attributes;
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.context.MessageContext;
SOA Summer School: SOA Enterprise Architecture Patterns by Asanka
This session will provide in-depth knowledge on how to implement an SOA solution using the basic elements in an SOA infrastructure. There will be several enterprise SOA patterns mapped to real world and hypothetical business requirements. Implementation details will be practically explained using the WSO2 SOA platform.
If you are yet to register - still its's open - further details here.
Guide to write XACML policies in WSO2 Identity Server 2.0 - Part - I
A given policy has an identifier, a rule combining algorithm, a description, a target and a set of rules.
Since, a given Policy may contain multiple Rules, each of which may evaluate to different access control decisions, XACML needs some way of reconciling the decisions each makes.
<Policy PolicyId="urn:sample:xacml:2.0:samplepolicy"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os">
<Description>Sample XACML Authorization Policy.</Description>
<Target>...</Target>
<Rule>...</Rule>
</Policy>
This is done through a collection of Combining Algorithms.
Each algorithm represents a different way of combining multiple descisions evaluated through different rules into a single descision.
Following rule combining algorithms are defined in XACML 2.0.
when we have urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable as the rule combining alogorithm, it will pick the first rule applicable from the defined set of Rules.
urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides
urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:permit-overrides
urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable
urn:oasis:names:tc:xacml:1.1:rule-combining-algorithm:ordered-denyoverrides
urn:oasis:names:tc:xacml:1.1:rule-combining-algorithm:ordered-permitoverrides
Once a XACML request being received at the PDP it needs to find a policy that applies to the corresponding request.
To do this, XACML uses the element Target.
A Target is basically a set of simplified conditions for the Subject, Resource and Action that must be met for a Policy or Rule to apply to a given request.
Once a Target is defined directly under Policy element - it defines the set of conditions that must be met to pick that Policy.
To make this very clear - let's go through an example.
<Policy PolicyId="urn:sample:xacml:2.0:samplepolicy"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os">
<Description>Sample XACML Authorization Policy.</Description>
<Target>
<Subjects>...</Subjects>
<Resources>...</Resources>
<Actions>...</Actions>
</Target>
<Rule>...</Rule>
</Policy>
This policy will be picked for a request having, any Subject, any Action on Resource http://localhost:8280/services/echo/.
For the time being, let's not worry too much about <Resources/> element.
<Policy PolicyId="urn:sample:xacml:2.0:samplepolicy"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os">
<Description>Sample XACML Authorization Policy.</Description>
<Target>
<Subjects> <AnySubject/> </Subjects>
<Resources>
<Resource>
<ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">http://localhost:8280/services/echo/</AttributeValue>
<ResourceAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</ResourceMatch>
</Resource>
</Resources>
<Actions> <AnyAction/> </Actions>
</Target>
<Rule>...</Rule>
</Policy>
Let's see another example. Here the Target is applied to the Rule - not to the entire Policy it self.
I guess, that explains enough about <Policy/> and <Target/> elements.
<Policy PolicyId="urn:sample:xacml:2.0:samplepolicy"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os">
<Description>Sample XACML Authorization Policy.</Description>
<Rule Effect="Permit" RuleId="primary-access-rule">
<Target>
<Subjects> <AnySubject/> </Subjects>
<Resources>
<Resource>
<ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">http://localhost:8280/services/echo/</AttributeValue>
<ResourceAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</ResourceMatch>
</Resource>
</Resources>
<Actions> <AnyAction/> </Actions>
</Target>
</Rule>
</Policy>
Let's move to the <Rule/> element. You may recall, that I mentioned there can be multiple Rule elements per given Policy.
Also - we discussed about Rule Combining Algorithms.
Let's focus on the child elements of the Rule element.
The way the Sun XACML engine determines whether a rule is applicable to an incoming request is by evaluating the Target and optional Condition (if it exists).
These are ANDed together, and the rule's effect achieved if the ANDed value is TRUE.
You know where Rule element fits in to a XACML policy - for the purpose of explaining, I'll just take out the isolated Rule element only - so keep in mind this is always within <Policy> tags.
A policy contains one or more Rules.
<Rule Effect="Permit" RuleId="primary-access-rule">
<Target>...</Target>
<Condition>...</Condition>
</Rule>
Each rule has a RuleId and an Effect.
An Effect is the intended consequence of a satisfied rule, which can be either "Deny" or "Permit." This means that if the rule is deemed applicable to an incoming service request, and the rule's conditions evaluate to TRUE, then the specified effect should be enforced.
Since we already discussed about the <Target/> element under the context of <Rule/>, we'll skip it here.
Let's focus on the <Condition/> element.
A Condition is a predicate that must be satisfied for a rule to be assigned its effect.
Okay - a Target defines a set of constraints for a Rule. So - what does a Condition do? Let's differentiate Condition from Target.
While Targets are appealing, frame-like expressions, they have a constrained logic which isn't always expressive enough to narrow down whether a policy is applicable to a service request.
Hence, the need for Condition element arises. If either the policy Target or the Rule Target is not able to adequately express a constraint, a Condition can be added to a Rule.
A Condition can only present within a Rule.
If a Condition is intended to be applicable to the entire Policy, the Condition must be repeated in every Rule in that Policy.
Let's go ahead with an example.
We want to restrict users based on their attributes.
Say - for example a given user has an accessList attribute - and we want to restrict access to a given resource based on the accessList.
I'll take an isolated <Condition/> element here...
Let's start from the inner most <Apply/> element.
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
<SubjectAttributeDesignator AttributeId="accessList" DataType="http://www.w3.org/2001/XMLSchema#string"/>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">nurses</AttributeValue>
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">doctors</AttributeValue>
</Apply>
</Apply>
</Condition>
It uses the string-bag function on two attributes.
This bag function wraps a set of possible values for the attribute defined under <SubjectAttributeDesignator/> element. In this case - possible values for the attribute 'accessList' should be either 'nurses' or 'doctors'.
Now, let's look at the outer most <Apply/> element. It uses string-at-least-one-member-of function which will be applied on the results of the inner function.
In other words - final condition says - if you want to access the resource you have to be a member of 'doctors' or 'nurses'.
This will basically conclude the part-1 of this series of blog posts.
In the next blog post I would like to write about Attributes and Attribute Designators.
Anatomy of the XACML Request
Let's started with breaking it down.
<Request xmlns="urn:oasis:names:tc:xacml:2.0:context:schema:os" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Subject>
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" DataType="http://www.w3.org/2001/XMLSchema#string">
<AttributeValue>admin</AttributeValue>
</Attribute>
<Attribute AttributeId="group" DataType="http://www.w3.org/2001/XMLSchema#string">
<AttributeValue>admin</AttributeValue>
</Attribute>
</Subject>
<Resource>
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" DataType="http://www.w3.org/2001/XMLSchema#string">
<AttributeValue>http://localhost:8280/services/echo/echoString</AttributeValue>
</Attribute>
</Resource>
<Action>
<Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" DataType="http://www.w3.org/2001/XMLSchema#string">
<AttributeValue>read</AttributeValue>
</Attribute>
</Action>
<Environment/>
</Request>
<Subject>
Represents the entity making the access request.
Can contain multiple <Attribute> elements.
A given Subject is identified by the attributes contained.
Each <Attribute> has two attributes. AttributeId and the DataType.
AttributeId can be a one of your own or one defined by the XACML specification.
Following are the set of special identifiers defined in XACML related to the Subject.
In our example, for the first Attribute under the Subject we use the special identifier, urn:oasis:names:tc:xacml:1.0:subject:subject-id. For the next Attribute, we use our own - 'group'. This can be anything - mail,givenName,accessList or any custom attribute - which could be identified by the defined XACML policy, where this request will be evaluated against.
urn:oasis:names:tc:xacml:1.0:subject:authn-locality:dns-name
urn:oasis:names:tc:xacml:1.0:subject:authn-locality:ip-address
urn:oasis:names:tc:xacml:1.0:subject:authentication-method
urn:oasis:names:tc:xacml:1.0:subject:authentication-time
urn:oasis:names:tc:xacml:1.0:subject:key-info
urn:oasis:names:tc:xacml:1.0:subject:request-time
urn:oasis:names:tc:xacml:1.0:subject:session-start-time
urn:oasis:names:tc:xacml:1.0:subject:subject-id
urn:oasis:names:tc:xacml:1.0:subject:subject-id-qualifier
urn:oasis:names:tc:xacml:1.0:subject-category:access-subject
urn:oasis:names:tc:xacml:1.0:subject-category:codebase
urn:oasis:names:tc:xacml:1.0:subject-category:intermediary-subject
urn:oasis:names:tc:xacml:1.0:subject-category:recipient-subject
urn:oasis:names:tc:xacml:1.0:subject-category:requesting-machine
The next attribute defined in the <Attribute> element is the DataType. It basically defines the type of data <AttributeValue> element should contain.
Following are set of data types defiend in XACML.
In our case both the Attributes are of type http://www.w3.org/2001/XMLSchema#string.
http://www.w3.org/2001/XMLSchema#string
http://www.w3.org/2001/XMLSchema#boolean
http://www.w3.org/2001/XMLSchema#integer
http://www.w3.org/2001/XMLSchema#double
http://www.w3.org/2001/XMLSchema#time
http://www.w3.org/2001/XMLSchema#date
http://www.w3.org/2001/XMLSchema#dateTime
http://www.w3.org/TR/2002/WD-xquery-operators-20020816#dayTimeDuration
http://www.w3.org/TR/2002/WD-xquery-operators-20020816#yearMonthDuration
http://www.w3.org/2001/XMLSchema#anyURI
http://www.w3.org/2001/XMLSchema#hexBinary
http://www.w3.org/2001/XMLSchema#base64Binary
urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name
urn:oasis:names:tc:xacml:1.0:data-type:x500Name
So, the bottom line is, the <Subject> element defines who wants to access.
<Resource>
This defines, the data,service or system component - which the Subject wants to access.
The <Resource> element contains one or more attributes of the resource to which the subject (or subjects) has requested access. There can be only one <Resource> per decision request.
Once again, a given <Resource> is identified by the <Attribute> child element. In our example, the Subject wants access to the Resource http://localhost:8280/services/echo/echoString.
<Action>
The <Action> element contains one or more attributes of the action that the subject (or subjects) wishes to take on the resource. There can be only one action per decision request.
Here also, a given <Action> is identified by the <Attribute> child element. In our example, the Subject wants Read access to the resource http://localhost:8280/services/echo/echoString.
<Environment>
A more complex request context may have contained some attributes not associated with the subject, the resource or the action. These would have been placed in an optional <Environment> element following the <Action> element.
Extending WSO2 Identity Server 2.0 to handle custom SAML assertions
Before reading this, you need to go through my previous blog post on 'WSO2 Identity Server + Claim aware proxy services with ESB' - available here.
Once you get the above running - all the client requests to attributes are satisfied through Identity Server's defaut implementation.
What if you need to filter attributes being sent?
What if you need to invoke an EJB to obtain custom attributes, and insert them as a SAML assertion to the returning security token?
In other words, you need to execute some custom logic in side Identity Server 2.0 to manipulate attributes being added to the returning security token... how to do this?
This blog post explains all what you need to make that happen.
First make sure - the first scenario works fine. That is, now you get the Security Token with SAML attribute assertions inserted by the Identity Server.
Now let's move to the second scenario - now we are going to override it.
Step -1
We need to write a carbon componet to insert our custom logic.
Please download the sample already written from here.
Extract the sample.aar. And run;
mvn clean install
from sample folder.[I have tested this with a clean maven repo].
Now, you can find the bundle inside, sample\org.wso2.carbon.identity.samples.attributeservice\target\org.wso2.carbon.identity.samples.attributeservice-2.0.0.SNAPSHOT.jar.
Step -2
Stop Identity Server [IS] if it's already running.
Copy org.wso2.carbon.identity.samples.attributeservice-2.0.0.SNAPSHOT.jar to [IS_HOME]\webapps\ROOT\WEB-INF\plugins\server
Open [IS_HOME]\webapps\ROOT\WEB-INF\eclipse\configuration\org.eclipse.equinox.simpleconfigurator\bundles.info and add the following entry to the end [one line].
org.wso2.carbon.identity.samples.attributeservice,2.0.0.SNAPSHOT,file:plugins/org.wso2.carbon.identity.samples.attributeservice-2.0.0.SNAPSHOT.jar,10,true
Start the IS with following.
\> wso2server.bat -DosgiConsole -cleanCache
Once got started - press <ENTER> on the console - you'll get the osgi prompt.
Type the following there - to list the available bundles.
osgi\> ss
Check the status of org.wso2.carbon.identity.samples.attributeservice bundle and get it's bundle ID [say 164]. If the status is RESOLVED then type;
osgi\> start 164
Now once again check the status with ss - it should be ACTIVE now.
Step -3
Run the same client used here before.
You'll see the 'First Name' attribute being overridden as well as a new attribute being added.
Also you'll see following line on the console.
INFO - SampleAttributeService being called
WSO2 Identity Server + Claim aware proxy services with ESB
Let me first briefly explain the the use case.
1. A proxy service created in WSO2 ESB requires a security token issued by the WSO2 Identity Server for authentication.
2.At the same time, the security policy in the proxy service, specifies - it requires a given set of claim values with the security token.
3. Identity Server is connected to an LDAP user store and all user attributes reside there.
<sp:RequestSecurityTokenTemplate xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
<t:KeyType>http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey</t:KeyType>
<t:KeySize>256</t:KeySize>
<t:Claims Dialect="http://wso2.org/claims" xmlns:ic="http://schemas.xmlsoap.org/ws/2005/05/identity">
<ic:ClaimType Uri="http://wso2.org/claims/givenname" />
</t:Claims>
</sp:RequestSecurityTokenTemplate>
4. User needs to authenticate to Identity Server, first and obtain the Security Token with claims.
5. Then user sends it to the ESB proxy service.
Let's see how we can achieve this in a step by step manner.
Step -1
Set up LDAP server. All the detail required explained here.
Step -2
Configure WSO2 Identity Server to talk to the LDAP Server and do the claim mapping. All the detail required explained here.
Step -3
Configure WSO2 Identity Server STS. The first part of this explains all the steps you need.
Before that you need to get the public certificate [wso2carbon.cert.cer] of the ESB from here.
Login to IS as an admin, and import the above certificate to wso2carbon.jks from Configure/Key Stores. [Yes - WSO2 ESB and IS use two different key stores - that's why we need to perform this step here]
Make sure, in the first step - while adding the trusted 'Endpoint Address' - select 'wso2carbon.cert' as the 'Certificate Alias'.
Also - while applying the security policy to the STS - make sure you select the group where ldap users[ldapuserole] belong to.
Step -4
Create and apply security for the proxy service. You need to follow exact steps defined here [first part] - but need to get the service security policy[service.policy.xml] from here, when you are overriding.
That's it - now let's write the client code.
You may also need to download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 5.0 from here and copy the two jar files from the extracted jce directory (local_policy.jar and US_export_policy.jar) to $JAVA_HOME/jre/lib/security. For JDK 6 it's here.
You need to do above, both at the client side as well as the server side - if you are running on two machines.
Also while running the client code, make sure bouncycastle jar is in the classpath.
You can download both sts.policy.xml and service.policy.xml files from here.
package org.apache.ws.axis2;
import java.util.Properties;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.apache.rahas.RahasConstants;
import org.apache.rahas.Token;
import org.apache.rahas.TokenStorage;
import org.apache.rahas.TrustUtil;
import org.apache.rahas.client.STSClient;
import org.apache.rampart.RampartMessageData;
import org.apache.rampart.policy.model.RampartConfig;
import org.apache.rampart.policy.model.CryptoConfig;
import org.apache.ws.secpolicy.Constants;
import org.opensaml.XML;
public class IdentitySTSClient {
/**
* @param args
*/
final static String RELYING_PARTY_SERVICE_EPR = "http://localhost:8280/services/echo";
final static String ESB_TRANS_EPR = "http://localhost:8280/services/test";
final static String STS_EPR = "https://localhost:9443/services/wso2carbon-sts";
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
ConfigurationContext confContext = null;
Policy stsPolicy = null;
STSClient stsClient = null;
Policy servicePolicy = null;
Token responseToken = null;
String trustStore = null;
// You need to import the Identity Server, public certificate to this key store.
// By default it's there - if you use wso2carbon.jks from [ESB_HOME]\resources\security
trustStore = "wso2carbon.jks";
// We are accessing STS over HTTPS - so need to set trustStore parameters.
System.setProperty("javax.net.ssl.trustStore", trustStore);
System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");
// Create configuration context - you will have Rampart module engaged in the
// client.axis2.xml
confContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repo",
"repo/conf/client.axis2.xml");
stsClient = new STSClient(confContext);
stsClient.setRstTemplate(getRSTTemplate());
stsClient.setAction(RahasConstants.WST_NS_05_02 + RahasConstants.RST_ACTION_SCT);
// This is the security policy we applied to Identity Server STS.
// You can see it by https://[IDENTITY_SERVER]/services/wso2carbon-sts?wsdl
stsPolicy = loadSTSPolicy("sts.policy.xml");
// This is the security of the relying party web service.
// This policy will accept a security token issued from Identity Server STS
servicePolicy = loadServicePolicy("service.policy.xml");
responseToken = stsClient.requestSecurityToken(servicePolicy, STS_EPR, stsPolicy,
RELYING_PARTY_SERVICE_EPR);
System.out.println(responseToken.getToken());
TokenStorage store = TrustUtil.getTokenStore(confContext);
store.add(responseToken);
ServiceClient client = new ServiceClient(confContext, null);
Options options = new Options();
options.setAction("urn:echoString");
options.setTo(new EndpointReference(RELYING_PARTY_SERVICE_EPR));
options.setProperty(org.apache.axis2.Constants.Configuration.TRANSPORT_URL, ESB_TRANS_EPR);
options.setProperty(RampartMessageData.KEY_RAMPART_POLICY, servicePolicy);
options.setProperty(RampartMessageData.KEY_CUSTOM_ISSUED_TOKEN, responseToken.getId());
client.setOptions(options);
client.engageModule("addressing");
client.engageModule("rampart");
OMElement response = client.sendReceive(getPayload("Hello world1"));
System.out.println("Response : " + response);
}
private static Policy loadSTSPolicy(String xmlPath) throws Exception {
StAXOMBuilder builder = null;
Policy policy = null;
RampartConfig rc = null;
builder = new StAXOMBuilder(xmlPath);
policy = PolicyEngine.getPolicy(builder.getDocumentElement());
rc = new RampartConfig();
// User from the LDAP user store
rc.setUser("prabath");
// You need to have password call-back class to provide the user password
rc.setPwCbClass(PWCBHandler.class.getName());
policy.addAssertion(rc);
return policy;
}
private static Policy loadServicePolicy(String xmlPath) throws Exception {
StAXOMBuilder builder = null;
Policy policy = null;
RampartConfig rc = null;
CryptoConfig sigCryptoConfig = null;
String keystore = null;
Properties merlinProp = null;
CryptoConfig encrCryptoConfig = null;
builder = new StAXOMBuilder(xmlPath);
policy = PolicyEngine.getPolicy(builder.getDocumentElement());
rc = new RampartConfig();
rc.setUser("wso2carbon");
rc.setEncryptionUser("wso2carbon");
// You need to have password call-back class to provide the user password
rc.setPwCbClass(PWCBHandler.class.getName());
keystore = "wso2carbon.jks";
merlinProp = new Properties();
merlinProp.put("org.apache.ws.security.crypto.merlin.keystore.type", "JKS");
merlinProp.put("org.apache.ws.security.crypto.merlin.file", keystore);
merlinProp.put("org.apache.ws.security.crypto.merlin.keystore.password", "wso2carbon");
sigCryptoConfig = new CryptoConfig();
sigCryptoConfig.setProvider("org.apache.ws.security.components.crypto.Merlin");
sigCryptoConfig.setProp(merlinProp);
encrCryptoConfig = new CryptoConfig();
encrCryptoConfig.setProvider("org.apache.ws.security.components.crypto.Merlin");
encrCryptoConfig.setProp(merlinProp);
rc.setSigCryptoConfig(sigCryptoConfig);
rc.setEncrCryptoConfig(encrCryptoConfig);
policy.addAssertion(rc);
return policy;
}
private static OMElement getRSTTemplate() throws Exception {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMElement element = null;
OMElement elem = fac.createOMElement(Constants.RST_TEMPLATE);
TrustUtil.createTokenTypeElement(RahasConstants.VERSION_05_02, elem).setText(XML.SAML_NS);
TrustUtil.createKeyTypeElement(RahasConstants.VERSION_05_02, elem,
RahasConstants.KEY_TYPE_SYMM_KEY);
TrustUtil.createKeySizeElement(RahasConstants.VERSION_05_02, elem, 256);
element = TrustUtil.createClaims(RahasConstants.VERSION_05_02, elem,"http://wso2.org");
addClaimType(element,"http://wso2.org/claims/givenname");
return elem;
}
private static void addClaimType(OMElement parent,String uri) {
OMElement element = null;
element = parent.getOMFactory().createOMElement(new QName("http://schemas.xmlsoap.org/ws/2005/05/identity", "ClaimType", "wsid"),
parent);
element.addAttribute( parent.getOMFactory().createOMAttribute("Uri",null,uri));
}
private static OMElement getPayload(String value) {
OMFactory factory = null;
OMNamespace ns = null;
OMElement elem = null;
OMElement childElem = null;
factory = OMAbstractFactory.getOMFactory();
ns = factory.createOMNamespace("http://echo.services.core.carbon.wso2.org", "ns1");
elem = factory.createOMElement("echoString", ns);
childElem = factory.createOMElement("in", null);
childElem.setText(value);
elem.addChild(childElem);
return elem;
}
}
package org.apache.ws.axis2;
import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
public class PWCBHandler implements CallbackHandler {
public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
WSPasswordCallback cb = (WSPasswordCallback) callbacks[0];
if ("prabath".equals(cb.getIdentifier())) {
cb.setPassword("prabath");
} else {
cb.setPassword("wso2carbon");
}
}
}
Connecting WSO2 Identity Server 2.0 to an LDAP based user store
Here, we'll be discussing all the steps required to deploy WSO2 Identity Server over an LDAP user store.
First we need to setup an LDAP server.
You may download Apache Directory Studio from here and set it up.
This explains all what you need to set it up.
1. Log in to Identity Server as an admin and go to User Manager and click on 'Add External User Store'.
2. Add your LDAP server settings and click Finish.
3. Click on 'Test Connection' to test the connectivity.
4. Click on 'External Users' and then 'Search' to list users from the external user store.
5. Go back to the previous screen and click on 'External Roles'. And then 'Add New Internal Roles'. Here we are going to create a new internal role for external users.
6. Give the new role a name.
7. Select a set of permissions.
8. Search users from the external user store and add them to the role.
9. Now - we need to map the LDAP attributes the claims read by Carbon.
10.Default claim dialect for Carbon is http://wso2.org/claims. Click on it - under 'External User Store'.
11.Click on the claims you want to change and set it's attribute name properly to the LDAP attribute.
That's and we are done. Now users from the LDAP user store can login to WSO2 Identity Server.
Setting up Apache Directory Server as the LDAP User Store
1. Start - Apache Directory Studio.
2. File --> New and select Apache DS Server
3. Window --> Show Views --> Other... select Servers
4. Right click on the 'wso2identity' server on the 'Servers' view and select 'Open Configuration'. Note that default port being set to 10389.
5. Window --> Show Views -->Connections and right click on the 'Connections' view to select 'New Connection...'.
6. Set hostname and port number of the server we just created.
7. Default password of admin is 'secret'.
8. Done. View the LDAP Browser. Now we are going to add a new user.Right click on 'ou=users' and select 'New Entry'.
9. Select 'inetOrgPerson' from left and add.
10.Set the attribute values for the user.
11.That's it - we are done.
Accessing proxy services in WSO2 ESB with a security token issued by the Identity Server 2.0
This is the use case;
1. User authenticates to the Identity Server 2.0
2. User gets a Security Token from the Identity Server 2.0 - which is signed by the Identity Server's private key and encrypted by the ESB's public key.
3. User provides the security token to the ESB to access the proxy service.
Lets create the proxy service first - you simply need to copy and paste following Synapse configuration [in WSO2 ESB] - it's a simple proxy service having a Send mediator in In/Out sequences.
<?xml version="1.0" encoding="UTF-8"?> <syn:definitions xmlns:syn="http://ws.apache.org/ns/synapse"> <syn:registry provider="org.wso2.carbon.mediation.registry.WSO2Registry"> <syn:parameter name="cachableDuration">15000</syn:parameter> </syn:registry> <syn:proxy name="test" transports="https http" startOnLoad="true" trace="disable"> <syn:target> <syn:inSequence> <syn:send/> </syn:inSequence> <syn:outSequence> <syn:send/> </syn:outSequence> </syn:target> </syn:proxy> <syn:sequence name="main"> <syn:in> <syn:log level="full"/> <syn:filter source="get-property('To')" regex="http://localhost:9000.*"> <syn:send/> </syn:filter> </syn:in> <syn:out> <syn:send/> </syn:out> </syn:sequence> <syn:sequence name="fault"> <syn:log/> </syn:sequence> </syn:definitions>Now, we need to apply security to the proxy service.
Lets select 'test' [the proxy service which we just created] from the service listing page and select 'Security' from the Service Dashboard.
Now, apply "Sign and encrypt - X509 Authentication" security policy and during the wizard select wso2carbon.jks as the trust store.
Once applied the security policy - we need to modify this to consume a security token issued by the Identity Server 2.0 STS.
From the Service Dashboard of the 'test' proxy service, select 'Policies'.
Let's get the policy to override, from service.policy.xml available here.
Click on "Edit Policy" at "Service Hierarchy\Service test" and clear the content there to copy & paste the content from service.policy.xml and Save.
Now we are done - our proxy service is secured - Sign & Encrypt and accepts a security token issued by the Identity Server STS.
Since, the token issued by the Identity Server 2.0 is signed by it's private key - ESB should have it's public key to verify. In default setup - ESB's trust key store includes the public certificate of the Identity Server - so, nothing to be done here with the default setup.
Now - we need to setup Identity Server STS to issue tokens.
As the first step - you need to upload the public certificate of the ESB to the Identity Server's trust key store - since IS uses it to encrypt the security token issued.
You can get the public certificate [wso2carbon.cert.cer] of the ESB from here.
Login to IS as an admin, and import the above certificate to wso2carbon.jks from Configure/Key Stores. [Yes - WSO2 ESB and IS use two different key stores - that's why we need to perform this step here]
The first part of this explains all the steps you need to setup IS STS.
Make sure, in the first step - while adding the trusted 'Endpoint Address' - select 'wso2carbon.cert' as the 'Certificate Alias'.
That's it - now let's write the client code.
You may also need to download Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 5.0 from here and copy the two jar files from the extracted jce directory (local_policy.jar and US_export_policy.jar) to $JAVA_HOME/jre/lib/security. For JDK 6 it's here.
Also while running the client code, make sure bouncycastle jar is in the classpath.
You can download both sts.policy.xml and service.policy.xml files from here.
package org.apache.ws.axis2; import java.util.Properties; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.OMNamespace; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.client.ServiceClient; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.apache.neethi.Policy; import org.apache.neethi.PolicyEngine; import org.apache.rahas.RahasConstants; import org.apache.rahas.Token; import org.apache.rahas.TokenStorage; import org.apache.rahas.TrustUtil; import org.apache.rahas.client.STSClient; import org.apache.rampart.RampartMessageData; import org.apache.rampart.policy.model.RampartConfig; import org.apache.rampart.policy.model.CryptoConfig; import org.apache.ws.secpolicy.Constants; import org.opensaml.XML; public class IdentitySTSClient { /** * @param args */ final static String RELYING_PARTY_SERVICE_EPR = "http://192.168.1.2:8280/services/echo"; final static String ESB_TRANS_EPR = "http://192.168.1.2:8280/services/test"; final static String STS_EPR = "https://localhost:9443/services/wso2carbon-sts"; /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { ConfigurationContext confContext = null; Policy stsPolicy = null; STSClient stsClient = null; Policy servicePolicy = null; Token responseToken = null; String trustStore = null; // You need to import the Identity Server, public certificate to this key store. // By default it's there - if you use wso2carbon.jks from [ESB_HOME]\resources\security trustStore = "wso2carbon.jks"; // We are accessing STS over HTTPS - so need to set trustStore parameters. System.setProperty("javax.net.ssl.trustStore", trustStore); System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon"); // Create configuration context - you will have Rampart module engaged in the // client.axis2.xml confContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repo", "repo/conf/client.axis2.xml"); stsClient = new STSClient(confContext); stsClient.setRstTemplate(getRSTTemplate()); stsClient.setAction(RahasConstants.WST_NS_05_02 + RahasConstants.RST_ACTION_SCT); // This is the security policy we applied to Identity Server STS. // You can see it by https://[IDENTITY_SERVER]/services/wso2carbon-sts?wsdl stsPolicy = loadSTSPolicy("sts.policy.xml"); // This is the security of the relying party web service. // This policy will accept a security token issued from Identity Server STS servicePolicy = loadServicePolicy("service.policy.xml"); responseToken = stsClient.requestSecurityToken(servicePolicy, STS_EPR, stsPolicy, RELYING_PARTY_SERVICE_EPR); System.out.println(responseToken.getToken()); TokenStorage store = TrustUtil.getTokenStore(confContext); store.add(responseToken); ServiceClient client = new ServiceClient(confContext, null); Options options = new Options(); options.setAction("urn:echoString"); options.setTo(new EndpointReference(RELYING_PARTY_SERVICE_EPR)); options.setProperty(org.apache.axis2.Constants.Configuration.TRANSPORT_URL, ESB_TRANS_EPR); options.setProperty(RampartMessageData.KEY_RAMPART_POLICY,servicePolicy); options.setProperty(RampartMessageData.KEY_CUSTOM_ISSUED_TOKEN, responseToken.getId()); client.setOptions(options); client.engageModule("addressing"); client.engageModule("rampart"); OMElement response = client.sendReceive(getPayload("Hello world1")); System.out.println("Response : " + response); } private static Policy loadSTSPolicy(String xmlPath) throws Exception { StAXOMBuilder builder = null; Policy policy = null; RampartConfig rc = null; builder = new StAXOMBuilder(xmlPath); policy = PolicyEngine.getPolicy(builder.getDocumentElement()); rc = new RampartConfig(); rc.setUser("admin"); // You need to have password call-back class to provide the user password rc.setPwCbClass(PWCBHandler.class.getName()); policy.addAssertion(rc); return policy; } private static Policy loadServicePolicy(String xmlPath) throws Exception { StAXOMBuilder builder = null; Policy policy = null; RampartConfig rc = null; CryptoConfig sigCryptoConfig = null; String keystore = null; Properties merlinProp = null; CryptoConfig encrCryptoConfig = null; builder = new StAXOMBuilder(xmlPath); policy = PolicyEngine.getPolicy(builder.getDocumentElement()); rc = new RampartConfig(); rc.setUser("wso2carbon"); rc.setEncryptionUser("wso2carbon"); // You need to have password call-back class to provide the user password rc.setPwCbClass(PWCBHandler.class.getName()); keystore = "wso2carbon.jks"; merlinProp = new Properties(); merlinProp.put("org.apache.ws.security.crypto.merlin.keystore.type","JKS"); merlinProp.put("org.apache.ws.security.crypto.merlin.file", keystore); merlinProp.put("org.apache.ws.security.crypto.merlin.keystore.password","wso2carbon"); sigCryptoConfig = new CryptoConfig(); sigCryptoConfig.setProvider("org.apache.ws.security.components.crypto.Merlin"); sigCryptoConfig.setProp(merlinProp); encrCryptoConfig = new CryptoConfig(); encrCryptoConfig.setProvider("org.apache.ws.security.components.crypto.Merlin"); encrCryptoConfig.setProp(merlinProp); rc.setSigCryptoConfig(sigCryptoConfig); rc.setEncrCryptoConfig(encrCryptoConfig); policy.addAssertion(rc); return policy; } private static OMElement getRSTTemplate() throws Exception { OMFactory fac = OMAbstractFactory.getOMFactory(); OMElement elem = fac.createOMElement(Constants.RST_TEMPLATE); TrustUtil.createTokenTypeElement(RahasConstants.VERSION_05_02, elem).setText(XML.SAML_NS); TrustUtil.createKeyTypeElement(RahasConstants.VERSION_05_02, elem,RahasConstants.KEY_TYPE_SYMM_KEY); TrustUtil.createKeySizeElement(RahasConstants.VERSION_05_02, elem, 256); return elem; } private static OMElement getPayload(String value) { OMFactory factory = null; OMNamespace ns = null; OMElement elem = null; OMElement childElem = null; factory = OMAbstractFactory.getOMFactory(); ns = factory.createOMNamespace("http://echo.services.core.carbon.wso2.org", "ns1"); elem = factory.createOMElement("echoString", ns); childElem = factory.createOMElement("in", null); childElem.setText(value); elem.addChild(childElem); return elem; } }
package org.apache.ws.axis2; import org.apache.ws.security.WSPasswordCallback; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.UnsupportedCallbackException; public class PWCBHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws UnsupportedCallbackException { WSPasswordCallback cb = (WSPasswordCallback) callbacks[0]; if ("admin".equals(cb.getIdentifier())) { cb.setPassword("admin"); } else { cb.setPassword("wso2carbon"); } } }
Adding fine-grained authorization for proxy services in WSO2 ESB
First you need to configure the WSO2 Identity Server 2.0 as the XACML engine and this explains how to do it.
WSO2 Identity Server 2.0 is a free and open source identity and entitlement management server, available to download from here...
Now, let's see how we can configure Entitlement mediator in the WSO2 ESB.
First, we are creating a proxy service going through the following wizard.
Under In Sequence- we are creating an Anonymous sequence - to include Entitlement,Header and Send mediators.
First let's add Advanced/Entitlement Mediator - to the InSequence.
Here, the Entitlement Server should be the endpoint from the Identity Server 2.0, where entitlement engine is running [https://[IDENTITY_SERVER]:[PORT]/services/].
And, the user we set there, should have login and manage configuration permissions in the Identity Server.
Now, let's add the Transform/Header mediator.
There you need to remove the 'Security' header. Click on the Namespaces link to set the wsse namespace.
Prefif : wsse
URI:http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd
Now, add a Core/Send mediator and save to return to the main flow.
Add a Core/Send mediator to the Out Sequence as an Anonymous sequence and save to return to the main flow - and complete creating the proxy service.
Now, we need to apply UsernameToken security policy to the proxy service we just created. This explains how to do it.
Here - we have a slight issue, since the security policy being applied to the binding by the policy editor - this has an issue with proxy services.
To overcome this, from the service listing, select the proxy service and then select 'Policies' - there remove the applied policies from the Binding Hierarchy and add that policy to the Service Hierarchy.
That's it - and all done - we are ready with the proxy service.
Now - we need to write a client to invoke the secured proxy service.
The following client tries to invoke the echo service deployed in ESB - through the proxy service we just created.
package org.apache.ws.axis2; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.OMNamespace; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.axis2.Constants; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.client.ServiceClient; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.apache.neethi.Policy; import org.apache.neethi.PolicyEngine; import org.apache.rampart.RampartMessageData; public class TestClient { final static String ADDR_URL = "http://192.168.1.2:8280/services/echo"; final static String TRANS_URL = "https://192.168.1.2:8243/services/test"; public static void main(String[] args) throws Exception { ServiceClient client = null; Options options = null; OMElement response = null; ConfigurationContext context = null; String trustStore = null; // You need to import the ESBs public certificate to this key store. trustStore = "mykeystore.jks"; // We are accessing ESB over HTTPS - so need to set trustStore parameters. System.setProperty("javax.net.ssl.trustStore", trustStore); // Password of mykeystore.jks System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon"); // Create configuration context - you will have Rampart module engaged in the client.axis2.xml context = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repo","repo/conf/client.axis2.xml"); // This is the security policy of the proxy service applied UT. StAXOMBuilder builder = new StAXOMBuilder("policy.xml"); Policy policy = PolicyEngine.getPolicy(builder.getDocumentElement()); context = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repo","repo/conf/client.axis2.xml"); client = new ServiceClient(context, null); options = new Options(); options.setAction("urn:echoString"); // This is the addressing URL pointing to the echo service deployed in ESB options.setTo(new EndpointReference(ADDR_URL)); // To the ESB, the proxy service options.setUserName("admin"); options.setPassword("admin"); // TRANS_URL points to proxy service options.setProperty(Constants.Configuration.TRANSPORT_URL, TRANS_URL); options.setProperty(RampartMessageData.KEY_RAMPART_POLICY, policy); client.setOptions(options); client.engageModule("addressing"); client.engageModule("rampart"); response = client.sendReceive(getPayload("Hello world")); System.out.println(response); } private static OMElement getPayload(String value) { OMFactory factory = null; OMNamespace ns = null; OMElement elem = null; OMElement childElem = null; factory = OMAbstractFactory.getOMFactory(); ns = factory.createOMNamespace("http://echo.services.core.carbon.wso2.org", "ns1"); elem = factory.createOMElement("echoString", ns); childElem = factory.createOMElement("in", null); childElem.setText(value); elem.addChild(childElem); return elem; } }
Identity Server 2.0 as an XACML engine
XACML support for fine-grained authorization comes with WSO2 Identity Server 2.0 for the first time as an experimental feature - though it includes full support for policies based on XACML 2.0.
To start with - you need to login to Identity Sever management console with an account having permissions login and manage configuration. That is, you can simply login with admin/admin.
1. Go to 'Policies' listed under 'Entitlement' menu.
2. There you can add a new policy or import external policy files to the system.
3. Once you click to add - it will simply add a template policy - where you can edit to suit your requirements - or you may add a complete new policy.
4. For the time being, I am just adding the template policy with no changes and let's see how to evaluate it - click on the 'Evaluate Entitlement Policies' link.
Here you can build your own XACML request to evaluate the policy just added.
Simply copy and paste the following on the above screen and click 'Evaluate'.
<Request xmlns="urn:oasis:names:tc:xacml:2.0:context:schema:os" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Subject> <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" DataType="http://www.w3.org/2001/XMLSchema#string"> <AttributeValue>admin</AttributeValue> </Attribute> <Attribute AttributeId="group" DataType="http://www.w3.org/2001/XMLSchema#string"> <AttributeValue>admin</AttributeValue> </Attribute> </Subject> <Resource> <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" DataType="http://www.w3.org/2001/XMLSchema#string"> <AttributeValue>http://localhost:8280/services/echo/echoString</AttributeValue> </Attribute> </Resource> <Action> <Attribute AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" DataType="http://www.w3.org/2001/XMLSchema#string"> <AttributeValue>read</AttributeValue> </Attribute> </Action> <Environment/> </Request>In plain English above request says, 'admin' user who belongs to the group 'admin' - trying to access the echoString operation of http://localhost:8280/services/echo service.
Now, let's see - how our template policy evaluates the above.
Find the following section of the template policy;
<Resources> <Resource> <ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">http://localhost:8280/services/echo/ <ResourceAttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" DataType="http://www.w3.org/2001/XMLSchema#string"/> </ResourceMatch> </Resource> </Resources>Here in this policy we use the function:string-regexp-match to validate the service name + operation name combination. You can modify it to suit your own requirement.
For example, if you want to allow users to access all the services deployed on a certain server, then simply change it to "http://localhost:8280/"
Or else, if you want user to access only a set of operations you can simply change the regex to http://localhost:8280/services/echo/(echoString|echoInt).
Now let's focus on the following code segment - it is to evaluate user name and his group
<Condition> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-is-in"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">admin</AttributeValue> <SubjectAttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" DataType="http://www.w3.org/2001/XMLSchema#string" SubjectCategory="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"/> </Apply> </Condition>
<Condition> <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-is-in"> <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">admin</AttributeValue> <SubjectAttributeDesignator AttributeId="group" DataType="http://www.w3.org/2001/XMLSchema#string"/> </Apply> </Condition>Here we validate user 'admin' or any user in the group 'admin'.
In future posts I'll further talk about how we could customize the template policy to fit into different business requirements.
Security Token Service with WSO2 Identity Server 2.0
This blog post explains how to access Identity Server 2.0 Security Token Service [STS] programmatically.
First you need to configure the Identity Server STS to issue security tokens.
Login as admin/admin to the management console and access 'Security Token Service'.
There you need to enter the relying parties you trust - in other words, which relying parties who will accept security tokens from the Identity Server.
You need to upload the public certificate of the trusted relying party - against it's end point.
When issuing tokens - it'll be encrypted from the public key of the trusted relying party.
So - even the client who obtains the token to send to the RP - has no visibility to the included token.
Now - let's apply security to the STS - here we provide UsernameToken based security - that means, to obtain a token from the STS, the client should have a valid user account with the Identity Server.
Click on the 'Apply Security Policy' link to configure security and go through the wizard.
That's it and that's all we need to configure Identity Server STS to issue security tokens.
Let's focus on the client code.
package org.apache.ws.axis2; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.apache.neethi.Policy; import org.apache.neethi.PolicyEngine; import org.apache.rahas.RahasConstants; import org.apache.rahas.Token; import org.apache.rahas.TrustUtil; import org.apache.rahas.client.STSClient; import org.apache.rampart.policy.model.RampartConfig; import org.apache.ws.secpolicy.Constants; import org.opensaml.XML; public class IdentitySTSClient { /** * @param args */ final static String RELYING_PARTY_SERVICE_EPR = "http://192.168.1.2:8280/services/echo"; final static String STS_EPR = "https://localhost:9443/services/wso2carbon-sts"; /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { ConfigurationContext confContext = null; Policy stsPolicy = null; STSClient stsClient = null; Policy servicePolicy = null; Token responseToken = null; String trustStore = null; // You need to import the Identity Server, public certificate to this key store. trustStore = "clientkeystore.jks"; // We are accessing STS over HTTPS - so need to set trustStore parameters. System.setProperty("javax.net.ssl.trustStore", trustStore); System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon"); // Create configuration context - you will have Rampart module engaged in the client.axis2.xml confContext = ConfigurationContextFactory.createConfigurationContextFromFileSystem("repo","repo/conf/client.axis2.xml"); stsClient = new STSClient(confContext); stsClient.setRstTemplate(getRSTTemplate()); stsClient.setAction(RahasConstants.WST_NS_05_02 + RahasConstants.RST_ACTION_SCT); // This is the security policy we applied to Identity Server STS. // You can see it by https://[IDENTITY_SERVER]/services/wso2carbon-sts?wsdl stsPolicy = loadPolicy("sts.policy.xml"); // This is the security of the relying party web service. // This policy will accept a security token issued from Identity Server STS servicePolicy = loadPolicy("service.policy.xml"); responseToken = stsClient.requestSecurityToken(servicePolicy, STS_EPR, stsPolicy, RELYING_PARTY_SERVICE_EPR); System.out.println(responseToken.getToken()); } private static Policy loadPolicy(String xmlPath) throws Exception { StAXOMBuilder builder = null; Policy policy = null; RampartConfig rc = null; builder = new StAXOMBuilder(xmlPath); policy = PolicyEngine.getPolicy(builder.getDocumentElement()); rc = new RampartConfig(); rc.setUser("admin"); // You need to have password call-back class to provide the user password rc.setPwCbClass(PWCBHandler.class.getName()); policy.addAssertion(rc); return policy; } private static OMElement getRSTTemplate() throws Exception { OMFactory fac = OMAbstractFactory.getOMFactory(); OMElement elem = fac.createOMElement(Constants.RST_TEMPLATE); TrustUtil.createTokenTypeElement(RahasConstants.VERSION_05_02, elem).setText(XML.SAML_NS); TrustUtil.createKeyTypeElement(RahasConstants.VERSION_05_02, elem, RahasConstants.KEY_TYPE_SYMM_KEY); TrustUtil.createKeySizeElement(RahasConstants.VERSION_05_02, elem, 256); return elem; } }
Subscribe to:
Posts (Atom)