Thursday, September 22, 2011

Virtual Users with SAML in WebLogic

A small blogpost how you can use virtual users on your SAML Service Provider WebLogic Server. A virtual user is a user who is authenticated on the SAML Identity Provider and this user is transfered ( with all his attributes and roles )  in a SAML Token to the Service Provider, this user does not need to exists on the WebLogic server of the Service Provider.
Before you can use this feature you need to setup SAML 2.0 SSO on your WebLogic Domain. You can follow this blogpost for all the instructions. You can also do this with Web Services but then you need to follow this guide.

First we need to enable Generate Attributes on the Identity Provider Side.
Go to the myrealm security realm ->  Providers -> Credentials Mapping -> your SAML 2.0 Credential Mapping Provider -> Provider Specific.
Also do this on the imported Service Provider Partner located at the Management tab of your SAML 2.0 Credential Mapping Provider. Open the Service Provider Partner and also enable here Generate Attributes.

Next step is to configure the SAML Service Provider.
Go to the myrealm security realm ->  Providers ->  Authentication -> your SAML 2.0 Identity Assertion Provider -> Management Tab.
Open your imported Identity Provider Partner configuration.
Enable Virtual User and also enable Process Attributes.

Now we need to add an extra WebLogic SAML Authentication Provider. This provider will process the virtual user SAML token with all its attributes and roles.
Set the Control Flag to Sufficient also change the other authentication provider from Required to Sufficient.

That's all.

22 comments:

  1. Hi Edwin,

    Good post, thank you very much!

    Just one question. I have set up a WLS as a service Provider. I would like that my applications would be able to use some user info that comes in the assertion.

    I have an implementation of the SAML2IdentityAsserterAttributeMapper in order to get the principals of the subject. After that I can get these principals through weblogic.security.principal.WLSUserImpl or weblogic.security.principal.WLGroupImpl.
    The problem is that through the principals I can only have access to the name, dn... and I would like to get some other info from the users like department, building...

    Thanks in advance,

    Luis

    ReplyDelete
  2. Hi,

    indeed I got the same problem , with owsm it works but with JAAS I dont get these ldap or saml attributes.

    I asked Oracle but they didnt gave a solution.

    thanks

    ReplyDelete
  3. Hi Edwin,

    For getting the assertion attribute values you just can make an implementation of the SAML2IdentityAsserterAttributeMapper.
    At the moment I have an implementation very similar to this: http://download.oracle.com/docs/cd/E17904_01/web.1111/e13711/saml.htm#CHDFHBHA

    Inside the for loop I have just do compararisons between the attributes name and the values that I need. This is, i.e., if I find the attribute name "Group", I take its value and store it as an instance of weblogic.security.principal.WLSGroupImpl.

    This approach could be ok. But the Oracle doc says:

    The attributes returned by the mapper are stored as subject principals or private credentials, depending on the class type of the mapped attributes. Specifically, if the mapper returns a collection of Principal objects, the mapped attributes are stored into the subject principal set. Otherwise, the subject private credential set is used to carry the mapped attributes.

    What I would like is to implement this second approach: store the attributes into the subject principal set.

    Hope it helps,

    Luis

    pd: At this moment I am not at the office, but If you want tomorrow I can send you my code (but is really simple, and it does not differ too much than the original from Oracle...)

    ReplyDelete
  4. Hi,

    Indeed, It should be the same as in this blog http://biemond.blogspot.com/2011/08/do-saml-with-owsm.html
    where I do the same with OWSM.

    Here I got a private principe
    SetaaaObjectaaa allPrivatePrincipals = subject.getPrivateCredentials();

    which is of instance SAMLAssertionToken and can read the attributes

    SAMLAssertionToken principal2 = (SAMLAssertionToken)principal; System.out.println("virtual found saml issuer: "+principal2.getIssuer()); Iterator it = principal2.getAttributeStatements().iterator(); while ( it.hasNext() ){ AttributeStatement attr = it.next(); Iterator it2 = attr.getSAMLAttributes().iterator() ; while ( it2.hasNext() ){ Attribute attr2 = it2.next(); System.out.println("SAML attribute: "+attr2.getAttributeName() ); IteratoraaaObjectaaa it3 = attr2.getAttributeValues().iterator() ; while ( it3.hasNext() ){ Object attr3 = it3.next(); System.out.println("value: "+attr3 ); } } }

    thanks

    ReplyDelete
  5. Hi Edwin,

    Thank you very much, another great post!

    Unfortunately it is not working for me.

    What I have done is this:

    In the Mapper Side:

    1. Implement the mapAttributeInfo method

    2. Implement my own CustomPrincipal:

    2.1 Implement my own CustomPrincipalValidator. Maybe here it is my weak point. I just return true in the sign() method, but I don't really sign my principal...


    And in the application side just try to get my principals:


    Subject subject = Security.getCurrentSubject();

    Set customPrincipals = subject.getPrincipals(CustomPrincipal.class);

    The problem is that all of of the principals that I get are instances of the WLSUserImpl

    Am I missing something?

    Thanks in advance,

    Luis

    ReplyDelete
  6. Hi

    can you send me the code and tell me how to configure weblogic console

    email biemond at gmail dot com

    thanks

    ReplyDelete
  7. Hi Edwin,

    Thank you very much for your answer!

    I have sent you my code and the admin console conf (screen captures) to biemond at gmail dot com

    Thanks in advance,

    Luis

    ReplyDelete
  8. Hi Edwin,

    Your blog is very interested to me. I have another issue with the SAML2IdentityAsserterAttributeMapper.

    In my case only mapNameInfo method is get called. The mapAttributeInfo method is not get called.

    I am using weblogic 10.3.5, and my saml 2.0 configurations are for web services.

    I have implemented the both interface SAML2IdentityAsserterNameMapper, SAML2IdentityAsserterAttributeMapper in one class. I have the configured implementaiton class
    in the Name Mapper Class Name: field of under the "Provider Specific" for the Saml2IdentityAsserter configurations.

    Am I missing something?


    Shahid

    ReplyDelete
  9. Hi Shahid,

    I faced this issue weeks ago. The problem was that the assertion did not have any , maybe you could check if yours have...

    If that is not the problem try mapping the class in the "Identity Provider Name Mapper Class Name".

    Cheers,

    Luis

    ReplyDelete
  10. Hi Luis,

    Thanks for your reply. Below is the SAML assertion I am getting:


    www.oracle.com

    Alice






    static.attribute.value



    Alice
    A


    Team
    Lead
    Programmer






    In the assertion I have attributes, but the mapAttributeInfo method is not get called.

    About my working environment: I am working with saml120sv (weblogic sample application). The both Identity provider and service provider are configured in one domain.


    Shahid

    ReplyDelete
  11. hi i was able to sucessfully implement the sam2.0 custom attribute mapper. i am not able to retrive the attributes in SP... due to incorrect implementation of CustomPrincipal. can anyone help me with the above code

    ReplyDelete
  12. Hi anonymous

    Your Custom Principal should look like this:

    public class CustomWlsPrincipal extends WLSAbstractPrincipal implements WLSUser {
    .../...

    Your custom attributes, setters, getters...

    And be careful with your constructors!!!

    public CustomWlsPrincipal(String name) {
    super();
    // Feed the WLSAbstractPrincipal.name. Mandatory
    this.setName(name);
    this.setCommonName(name);
    .../...
    }

    public CustomWlsPrincipal() {
    super();
    .../...
    }

    And also:

    public void setCommonName(String commonName) {
    // Feed the WLSAbstractPrincipal.name. Mandatory
    super.setName(commonName);
    this.commonName = commonName;
    }

    And do not forget to implement the equals() and hashCode(). I use the default proposed by my IDE (Eclipse)

    }

    Hope it helps,

    Luis

    ReplyDelete
  13. Hi Luis!
    I have the same problem: "only mapNameInfo method is get called. The mapAttributeInfo method is not get called."
    Did You found solution?
    Can you tell, how you solve the problem with more details?
    You wrote: "The problem was that the assertion did not have any".
    Can You give a example: assertation did not have some attribute or anything other?

    Thanks!
    Hal

    ReplyDelete
  14. Hi Hal,

    Yes, fortunately I found it:

    1. Security Realms --> myrealm --> providers --> myIdentityAsserter --> Configuration --> Provider Specific--> Name Mapper Class Name: your.mapper.Class This class MUST be in the System Classpath! For this you can add it to the EXT_PRE or EXT_POST CLASSPATH in the setDomainEnv.sh.

    2. your.mapper.Class MUST implement SAML2IdentityAsserterAttributeMapper, SAML2IdentityAsserterNameMapper

    3. In the mapAttributeInfo just iterate over the list of attributes and get their values:

    @Override
    public Collection mapAttributeInfo(
    Collection attrStmtInfos,
    ContextHandler contextHandler) {

    if (attrStmtInfos == null || attrStmtInfos.size() == 0) {
    return null;
    }

    Collection principals = new ArrayList();

    MyWlsPrincipal myWlsPrincipal = new MyWlsPrincipal();

    for (SAML2AttributeStatementInfo stmtInfo : attrStmtInfos) {
    Collection attrs = stmtInfo.getAttributeInfo();
    if (attrs == null || attrs.size() == 0) {
    System.out
    .println(this.getClass().getCanonicalName()
    + ": no attribute in statement: "
    + stmtInfo.toString());
    } else {
    for (SAML2AttributeInfo attr : attrs) {
    for (Attribute attribute : Attribute.values()) {
    if (attr.getAttributeName().equals(attribute.getName())) {
    if(attr.getAttributeValues().size()>1){
    attribute.setValue(myWlsPrincipal, attr
    .getAttributeValues());
    } else {
    attribute.setValue(myWlsPrincipal, attr
    .getAttributeValues().iterator().next());
    }
    break;
    }
    }
    }
    }
    }

    That's it!

    An example of "void" assertion could be this: if you install an IdP "out-of-the-box", for example OPenAM, if you do not add any claim in the configuration, when you get the assertion response you will see that there are no attributes at all.

    Hope it helps,

    Luis

    ReplyDelete
  15. hiiii dear,
    thanks for your great article, but my problem is:

    i have APP_A with FORM and APP_B with CLIENT-CERT i have configured SSO on source and dest as your previous article
    problem appeared when i want to go back from APP_B to APP_A i get the login page again !!!!!!!!
    tried to add virtual user to overcome this issue but i couldn't ...

    any idea please...

    ReplyDelete
  16. hi Edwin,

    I have an application which is running on weblogic 10.3.5 , and i want to implement sso for an sap netweaver, how to configure SAML based sso between two applications any idea

    regards
    shekar

    ReplyDelete
  17. Dear Edwin,

    In our company we have configured a POC for SSO with SAML for authorization of users against ADFS V2 successfully. We only require that the user is authenticated, any user within the company should be allowed to see it. The issue that we have is that it seems that if we remove the role constraint then anyone is allowed and is not being authenticated in ADFS. The only way it works is defining a role and the users that are part of that role and restricting the access to that role. Would it be possible to configure Weblogic just to let any user authenticated in ADFS to see the page no matter the role it has?

    Thanks in advance.

    Kind regards,

    Jorge.

    ReplyDelete
    Replies
    1. Hello Jorge,

      Mapping your role against the principal "users" will do the trick. e.g.

      in your web.xml you declare your security-constraint with a role-name of your choice. Declare this role in a security-role element.

      In your weblogic.xml map the above role against the "users" principal in the security-role-assignment element

      Hope it helps,

      Luis


      Delete
    2. Thank you Luis for your reply,

      I think you mean defining in weblogic.xml something like:


      admin -->
      user1
      ...
      userN


      This approach worked in our case. The issue is that we have as many user as employees in the company and we can not map all the users in this file.

      We are looking for a solution that allows to connect any user authenticated regardless of the role. As long as it was authenticated with ADFS it should be allowed to enter.

      We have tried to use wildcards in web.xml such as:


      *


      .....


      *


      Unfortunately using this approach we always obtain a 403 error after being successfully authenticated in ADFS. It seems that the user needs to be defined in a role and that role needs to be authorized.


      Kind regards,

      Jorge.

      Delete
    3. Finally I was able to make it work with wildcards (*) for roles and setting up this:

      From the weblogic console Home -> Domain -> Web Applications -> Turn on "Allow All Roles"

      Kind regards,

      Jorge.

      Delete
    4. Hello Jorge,

      What I meant was that the principal "users" refers to all authenticated users. You can see it as a kind of wildcard.

      Good to hear that is working also with the "*" trick in the console, good hint, thanks!

      Cheers,

      Luis

      Delete