Secure Web Services Using Identity Cloud Service

Use Oracle Identity Cloud Service and Oracle Web Services Manager to protect web service applications and clients that you deploy to Oracle WebLogic Server for OCI domains.

This configuration is applicable only for domains that you created with Oracle WebLogic Server for OCI, and that meet all of these requirements:

All JRF-enabled domains include Oracle Web Services Manager (OWSM), which provides a policy framework to manage and secure web services consistently across your organization. Both Oracle Web Services Manager and Oracle Identity Cloud Service support the OAuth protocol. The web service client requests an access token by authenticating with the authorization server (Oracle Identity Cloud Service) and presenting the authorization grant. The Oracle Web Services Manager server-side agent validates the access token and then accepts the client request if valid.

See Using OAuth2 with Oracle Web Services Manager in Securing Web Services and Managing Policies with Oracle Web Services Manager.

When you secure web service communication, the following terms are used:

  • Provider - The Oracle WebLogic Server for OCI stack (WebLogic Server domain, load balancer, and so on) that hosts your web service application.
  • Client - The Oracle WebLogic Server for OCI stack that hosts your web service client application.

The following diagram illustrates this security configuration.

Description of architecture_idcs_owsm_diagram.png follows
Description of the illustration architecture_idcs_owsm_diagram.png

Deploy a Sample Web Service Client Application

To quickly verify the OAuth integration between Oracle Web Services Manager and Oracle Identity Cloud Service, you can build and deploy a sample client application.

This sample web application consists of a single page with an HTML form, and a single Servlet that invokes the specified web service URL. The client uses the OAuth policy oracle/http_oauth2_token_over_ssl_idcs_client_policy.

Alternatively, you can deploy and test your own web service client application.

  1. Connect to the Administration Server node in your client domain as the opc user.
    ssh -i <path_to_private_key> opc@<node_public_ip>
  2. Change to the oracle user.
    sudo su - oracle
  3. Create the web application directory structure.
    mkdir -p /home/oracle/oauth-client/WEB-INF/classes
  4. Copy and paste the following text into a new file named /home/oracle/oauth-client/index.jsp.
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html"/>
        <title>Test web services call using wss-oauth</title>
    </head>
    <body>
    <form name="oauth-test" method="post" action="helloworldclientservlet">
        <table>
            <tr>
                <th>Address</th>
                <td>
                    <input name="address" type="text" size="110" value=""/>
                </td>
            </tr>
            <tr>
                <th>Scope</th>
                <td>
                    <input name="scope" type="text" size="110" value=""/>
                </td>
            </tr>
            <tr>
                <th>Test</th>
                <td>
                    <input name="submit" type="submit" size="20" value="Test"/>
                </td>
            </tr>
        </table>
    </form>
    </body>
    </html>
  5. Copy and paste the following text into a new file named /home/oracle/HelloWorldClientServlet.java.
    import java.util.*;
    import java.io.*;
    import java.lang.*;
    import java.security.AccessController;
    import javax.security.auth.Subject;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import weblogic.jaxrs.api.client.Client;
    import com.sun.jersey.api.client.WebResource;
    import com.sun.jersey.api.client.config.DefaultClientConfig;
    import com.sun.jersey.api.client.filter.LoggingFilter;
    import com.sun.jersey.api.client.ClientResponse;
    import oracle.wsm.metadata.feature.AbstractPolicyFeature;
    import oracle.wsm.metadata.feature.PolicyReferenceFeature;
    import oracle.wsm.metadata.feature.PolicySetFeature;
    import oracle.wsm.metadata.feature.PropertyFeature;
    import oracle.wsm.security.util.SecurityConstants;
    
    public class HelloWorldClientServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest request,
                              HttpServletResponse response) throws ServletException, IOException {
            response.setContentType("text/plain");
            PrintWriter out = response.getWriter();
            String BASE_URI = request.getParameter("address");
            String SCOPE_URI = request.getParameter("scope");
            PropertyFeature scope = new PropertyFeature(SecurityConstants.ConfigOverride.CO_SCOPE, SCOPE_URI);
            PolicyReferenceFeature clientPRF = new PolicyReferenceFeature("oracle/http_oauth2_token_over_ssl_idcs_client_policy", scope);
            DefaultClientConfig cc = new DefaultClientConfig();
            Map<String, Object> properties = cc.getProperties();
            properties.put(AbstractPolicyFeature.ABSTRACT_POLICY_FEATURE, new PolicySetFeature(clientPRF));
            Client client = Client.create(cc);
            OutputStream baos = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(baos);
            client.addFilter(new LoggingFilter(ps));
            try {
                Subject subject = Subject.getSubject(AccessController.getContext());
                Set<java.security.Principal> principals = subject.getPrincipals();
                for (java.security.Principal principal : principals) {
                    out.println("principal : " + principal.toString());
                }
                WebResource webResource = client.resource(BASE_URI);
                ClientResponse res = webResource.get(ClientResponse.class);
                ps.flush();
                out.println(baos.toString());
            } catch (Exception e) {
                String[] messages = getAllInnerErrorMessages(e);
                int count = 0;
                String allMsg = null;
                for (String mes : messages) {
                    if (count != 0) {
                        allMsg += "\n|";
                        allMsg = allMsg + "\n+" + (getString("-", count * 3) + "-> Caused By : " + mes);
                    } else {
                        allMsg = mes;
                    }
                    count++;
                }
                out.println("The client was not able to call the service using OAuth. The exception causes are: \n" + allMsg);
            }
            out.close();
        }
     
        private String[] getAllInnerErrorMessages(Throwable th) {
            List<String> all = new ArrayList<String>();
            boolean msgFound = false;
            while (th != null) {
                if (th.getMessage() != null && !th.getMessage().trim().equals("")) {
                    if (!msgFound && all.size() > 0) {
                        all.add(0, th.getMessage());
                    }
                    all.add(th.getMessage());
                    msgFound = true;
                } else {
                    all.add(th.getClass().getName());
                }
                th = th.getCause();
            }
            return all.toArray(new String[0]);
        }
     
        private String getString(String sp, int count) {
            StringBuffer ret = new StringBuffer();
            for (int i = 0; i < count; i++) {
                ret.append(sp);
            }
            return ret.toString();
        }
     
    }
  6. Copy and paste the following text into a new file named /home/oracle/oauth-client/WEB-INF/web.xml.
    <?xml version = '1.0' encoding = 'windows-1252'?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
        <servlet>
            <servlet-name>HelloWorldClientServlet</servlet-name>
            <servlet-class>HelloWorldClientServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>HelloWorldClientServlet</servlet-name>
            <url-pattern>/helloworldclientservlet</url-pattern>
        </servlet-mapping>
        <security-constraint>
            <web-resource-collection>
                <web-resource-name>Success</web-resource-name>
                <url-pattern>/index.jsp</url-pattern>
            </web-resource-collection>
        </security-constraint>
        <login-config>
            <auth-method>CLIENT-CERT</auth-method>
        </login-config>
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    </web-app>
  7. Run setWLSEnv.sh.
    source /u01/app/oracle/middleware/wlserver/server/bin/setWLSEnv.sh
  8. Compile the Servlet and put the class file in /home/oracle/oauth-client/WEB-INF/classes.
    cd /home/oracle
    javac -cp $CLASSPATH:/u01/app/oracle/middleware/oracle_common/modules/clients/com.oracle.webservices.wls.jaxws-owsm-client.jar \
    -d /home/oracle/oauth-client/WEB-INF/classes \
    HelloWorldClientServlet.java
  9. Package the application.
    cd oauth-client
    zip -r ../oauth-client.war *
    cd ..
  10. Use the WebLogic Scripting Tool (WLST) to deploy oauth-client.war to your domain.
    /u01/app/oracle/middleware/oracle_common/common/bin/wlst.sh
    connect('<admin_user>','<admin_password>','t3://<admin_server_IP>:<admin_server_port>')
    deploy(appName='oauth-client',path='/home/oracle/oauth-client.war',targets='<server_or_cluster>',upload='true')

    Example:

    /u01/app/oracle/middleware/oracle_common/common/bin/wlst.sh
    connect('weblogic','<admin_password>','t3://203.0.113.20:7001')
    deploy(appName='oauth-client',path='/home/oracle/oauth-client.war',targets='wlsoci_cluster',upload='true')

Get Information About Identity Cloud Service

Record configuration details about your Oracle Identity Cloud Service instance, and also download its certificates.

Before you begin, identify the confidential application in Oracle Identity Cloud Service that was created for your web services client domain. See Identity Resources for Oracle Identity Cloud Service.

  1. Access the Oracle Identity Cloud Service console.
  2. From the navigation menu, click Applications.
  3. Click the confidential application that was created for your client domain.
  4. Click the Configuration tab.
  5. Under General Information, copy the Client ID.
  6. Click Show Secret, and then copy the secret value.
  7. From the navigation menu, click Settings, and then click Default Settings.
  8. If it's not already enabled, select Access Signing Certificate, click Save, and then click Yes.
  9. Access the following URL: https://idcs-GUID.identity.oraclecloud.com/admin/v1/SigningCert/jwk

    You can obtain the GUID for your Oracle Identity Cloud Service instance from the console URL.

    The response contains two certificates, separated by a comma.

    {"keys":[{"kty":"RSA",...,"kid":"SIGNING_KEY",...:
    ["<idcs_cert>","<idcs_root_ca_cert>"],"key_ops":
    ["verify","encrypt"],"alg":"RS256",...}]}
  10. Copy and paste the first certificate, idcs_cert, into a new file named idcs.cert.
    Add the standard certificate header and footer lines.
    -----BEGIN CERTIFICATE-----
    <idcs-cert>
    -----END CERTIFICATE-----
  11. Copy and paste the second certificate, idcs_root_ca_cert, into a new file named idcs_ca.cert.
    Add the standard certificate header and footer lines.
    -----BEGIN CERTIFICATE-----
    <idcs_root_ca_cert>
    -----END CERTIFICATE-----
  12. Use openssl to view idcs.cert in text format.
    openssl x509 -in idcs.cert -text
  13. Copy the contents of the Subject field, which contains a list of distinguished names (DN).
    Certificate:
        Data:
            ...
            Validity
                Not Before: Aug 27 09:20:19 2019 GMT
                Not After : Aug 27 09:20:19 2029 GMT
            Subject: <dn_list>
            ...
  14. Use openssl to view idcs_ca.cert in text format, and to verify that it has no validation errors.
    openssl x509 -in idcs_ca.cert -text
  15. Access the following URL: https://idcs-GUID.identity.oraclecloud.com/.well-known/idcs-configuration
  16. From the response, copy the values for issuer and token_endpoint.
    For example:
    {
      ...
      "openid-configuration" : {
        "issuer" : "https://identity.oraclecloud.com/",
        "authorization_endpoint" : "https://idcs-GUID.identity.oraclecloud.com/oauth2/v1/authorize",
        "token_endpoint" : "https://idcs-GUID.identity.oraclecloud.com/oauth2/v1/token",
        ...
  17. Return to the Oracle Identity Cloud Service console, click Settings, and then click Default Settings.
  18. If Access Signing Certificate was disabled previously, then disable it again. Click Save, and then click Yes.

Configure OAuth for the Web Services Provider

Establish trust between Oracle Web Services Manager in your provider domain and Oracle Identity Cloud Service by importing certificates and creating global policy attachments.

The global policy affects all web services deployed to this domain. Alternatively, you can create policies for individual web services.

  1. Copy the files idcs.cert and idcs_ca.cert to the Administration Server node in your provider domain as the opc user.
    Place the files in the /tmp directory.
    scp -i <path_to_private_key> idcs.cert opc@<node_public_ip>:/tmp
    scp -i <path_to_private_key> idcs_ca.cert opc@<node_public_ip>:/tmp
  2. Connect to the Administration Server node in your domain as the opc user.
    ssh -i <path_to_private_key> opc@<node_public_ip>
  3. Change the owner of the certificate files to oracle.
    sudo chown oracle:oracle /tmp/*.cert
  4. Change to the oracle user.
    sudo su - oracle
  5. Copy and paste the following text into a new file named config_owsm_provider.py.
    ip='<admin_server_IP>'
    port='<admin_server_port>'
    user='<admin_user>'
    pwd='<password>'
    dn_list='<idcs_dn_list>'
    trusted_issuer='<issuer>'
    idcs_cert_path = '/tmp/idcs.cert'
    idcs_ca_cert_path = '/tmp/idcs_ca.cert'
  6. Update the variables in config_owsm_provider.py.
    • The IP address of this node
    • The port number of the Administration Server (the default is 7001)
    • The user name and password of the domain administrator
    • The distinguished name (DN) from the Subject field in idcs.cert.
    • The Oracle Identity Cloud Service issuer name

    Reverse the order of the DN entries. For example, change CN = abc,CN = def to CN = def,CN = abc.

    For example:

    ip='203.0.113.20'
    port='7001'
    user='weblogic'
    pwd='<password>'
    dn_list='CN=idcs-GUID,CN=Cloud9,CN=sslDomains'
    trusted_issuer='https://identity.oraclecloud.com/'
    
  7. Copy and paste the following text into config_owsm_provider.py, and after the variable declarations.
    connect(user, pwd,'t3://' + ip + ':' + port)
    
    try:
       beginWSMSession()
       createWSMPolicySet('oauth-ps-ws-service','ws-service','Domain("*")','Global policy for default interactions for ws-service',true)
       attachWSMPolicy('oracle/wss11_saml_or_username_token_with_message_protection_service_policy')   
       validateWSMPolicySet('oauth-ps-ws-service')
       displayWSMPolicySet('oauth-ps-ws-service')
    finally:
       commitWSMSession()
    
    try:
       beginWSMSession()
       createWSMPolicySet('oauth-ps-rest-resource','rest-resource','Domain("*")','Global policy for default interactions for rest-resource',true)
       attachWSMPolicy('oracle/multi_token_over_ssl_rest_service_policy')
       validateWSMPolicySet('oauth-ps-rest-resource')
       displayWSMPolicySet('oauth-ps-rest-resource')
    finally:
       commitWSMSession()
    
    try:
       beginWSMSession()
       createWSMTokenIssuerTrustDocument('trust-doc',None)
       setWSMConfiguration(None, 'TokenIssuerTrust', 'name', None, ['trust-doc'])
       selectWSMTokenIssuerTrustDocument('trust-doc')
       setWSMTokenIssuerTrust('dns.jwt',trusted_issuer,[dn_list])
       setWSMTokenIssuerTrust('dns.sv',trusted_issuer,[dn_list])
       setWSMTokenIssuerTrust('dns.hok',trusted_issuer,[dn_list])
       setWSMTokenIssuerTrust('dns.jwt','www.oracle.com',[])
       setWSMTokenIssuerTrust('dns.sv','www.oracle.com',[])
       setWSMTokenIssuerTrust('dns.hok','www.oracle.com',[])
    finally:
       commitWSMSession()
    
    refreshWSMCache()
    
    svc=getOpssService(name='KeyStoreService')
    try:
       svc.createKeyStore(appStripe='owsm', name='keystore', password='',permission=true)
    except Exception, ex:
       ex_msg = str(ex)
       if 'Keystore keystore in stripe owsm already exists' in ex_msg:
          print 'Keystore keystore in stripe owsm already exists. Continue...'
       else:
          raise
    svc.importKeyStoreCertificate(appStripe='owsm', name='keystore', password='', alias='idcs-oauthkey', keypassword='', type='TrustedCertificate', filepath=idcs_cert_path)
    svc.importKeyStoreCertificate(appStripe='owsm', name='keystore', password='', alias='idcs-oauthkeyca', keypassword='', type='TrustedCertificate', filepath=idcs_ca_cert_path)
  8. Run config_owsm_provider.py using WLST.
    /u01/app/oracle/middleware/oracle_common/common/bin/wlst.sh config_owsm_provider.py

    Verify that the script ran successfully:

    ...
    Session started for modification.
    The policy set was created successfully in the session.
    Policy reference "oracle/wss11_saml_or_username_token_with_message_protection_service_policy" added.
    ...
    Creating policy set oauth-ps-ws-service in repository.
    Session committed successfully.
    Session started for modification.
    The policy set was created successfully in the session.
    Policy reference "oracle/multi_token_over_ssl_rest_service_policy" added.
    ...
    Creating policy set oauth-ps-rest-resource in repository.
    Session committed successfully.
    Session started for modification.
    New Token Issuer Trust document named trust-doc created.
    ...
    Creating tokenissuertrust trust-doc in repository.
    Session committed successfully.
    ...
    Keystore created
    Certificate imported.
    Certificate imported.

Update the Confidential Application for the Web Services Provider

Update the resources that are protected by OAuth in the domain's confidential application found in Oracle Identity Cloud Service.

  1. Access the Oracle Identity Cloud Service console.
  2. From the navigation menu, click Applications.
  3. Click the confidential application that was created for your provider domain.
  4. Click the Configuration tab.
  5. Under Resources, click Register Resources.
  6. For Primary Audience, enter the URL of the load balancer that directs traffic to the provider domain.
    https://<lb_public_ip>:443
  7. For Scopes, click Add.
  8. Set the name of the new scope to external, and then click Add.
  9. Click Save.

Configure OAuth for the Web Services Client

Establish trust between Oracle Web Services Manager in your client domain and Oracle Identity Cloud Service by importing certificates and creating global policy attachments.

The global policy affects all web service clients deployed to this domain. Alternatively, you can create policies for individual applications.

  1. Connect to the Administration Server node in your client domain as the opc user.
    ssh -i <path_to_private_key> opc@<node_public_ip>
  2. Change to the oracle user.
    sudo su - oracle
  3. Copy and paste the following text into a new file named config_owsm_client.py.
    def config_policyset(policy_set_name,subject_type):
        try:
            beginWSMSession()
            createWSMPolicySet(policy_set_name,subject_type,resource_scope,desc,is_enabled)
            attachWSMPolicy(policy)
            setWSMPolicyOverride(policy,'token.uri',token_uri)
            setWSMPolicyOverride(policy,'oauth2.client.csf.key',csf_key)
            validateWSMPolicySet(policy_set_name)
        finally:
            commitWSMSession()
            displayWSMPolicySet(policy_set_name)
     
    ip='<admin_server_IP>'
    port='<admin_server_port>'
    user='<admin_user>'
    pwd='<password>'
    client_id='<idcs_app_client_id>'
    client_secret='<idcs_app_client_secret>'
    token_uri = '<token_endpoint>'
    dn_list = '<dn_list>'
    app_resource = 'resource=<client_app_name>'
  4. Update the variables in config_owsm_client.py.
    • The IP address of this node
    • The port number of the Administration Server (the default is 7001)
    • The user name and password of the domain administrator
    • The client ID and secret of the confidential application in Oracle Identity Cloud Service that was created for the domain
    • The Oracle Identity Cloud Service token endpoint
    • The distinguished name (DN) to use for the generated certificate in Oracle Web Services Manager
    • The name of the web service client application that is deployed to the domain

    For example:

    ip='203.0.113.30'
    port='7001'
    user='weblogic'
    pwd='<password>'
    client_id='ABCD1234efgh5678IJKL9012'
    client_secret='<idcs_app_client_secret>'
    token_uri = 'https://idcs-1234abcd5678EFGH9012ijkl.identity.oraclecloud.com/oauth2/v1/token'
    dn_list = 'CN=OWSM, OU=ST, O=Oracle, L=RedWood, ST=CA, C=US'
    app_resource = 'resource=oauth-client'
  5. Copy and paste the following text into config_owsm_client.py, and after the variable declarations.
    connect(user, pwd,'t3://' + ip + ':' + port)
    
    csf_key = 'idcs.oauth2.client.credentials'
    createCred(map='oracle.wsm.security',key=csf_key,user=client_id,password=client_secret)
    
    is_enabled = true
    policy = 'oracle/oauth2_config_client_policy'
    resource_scope = 'Domain("*")'
    desc = ''
    config_policyset('oauth-ps-config-rest-connection','rest-connection')
    config_policyset('oauth-ps-config-rest-client','rest-client')
    config_policyset('oauth-ps-config-ws-connection','ws-connection')
    config_policyset('oauth-ps-config-ws-client','ws-client')
    config_policyset('oauth-ps-config-ws-callback','ws-callback')
    refreshWSMCache()
    
    svc = getOpssService(name='KeyStoreService')
    try:
       svc.createKeyStore(appStripe='owsm', name='keystore', password='',permission=true)
    except Exception, ex:
       ex_msg = str(ex)
       if 'Keystore keystore in stripe owsm already exists' in ex_msg:
          print 'Keystore keystore in stripe owsm already exists. Continue...'
       else:
          raise
    svc.generateKeyPair(appStripe='owsm', name='keystore', password='', dn=dn_list, keysize='2048', alias='orakey', keypassword='')
     
    svc.exportKeyStoreCertificate(appStripe='owsm', name='keystore', password='', alias='orakey', keypassword='', type='TrustedCertificate', filepath='/tmp/orakey.cert')
    
    grantPermission(appStripe=None, codeBaseURL='file:${common.components.home}/modules/oracle.wsm.common/wsm-agent-core.jar',principalClass=None,principalName=None,permClass='oracle.wsm.security.WSIdentityPermission',permTarget=app_resource, permActions='assert')
    
  6. Run config_owsm_client.py using WLST.
    /u01/app/oracle/middleware/oracle_common/common/bin/wlst.sh config_owsm_client.py

    Verify that the script ran successfully:

    ...
    Credential created successfully.
    Session started for modification.
    The policy set was created successfully in the session.
    Policy reference "oracle/oauth2_config_client_policy" added.
    ...
    Creating policy set oauth-ps-config-rest-connection in repository.
    Session committed successfully.
    ...
    Session started for modification.
    The policy set was created successfully in the session.
    Policy reference "oracle/oauth2_config_client_policy" added.
    ...
    Creating policy set oauth-ps-config-rest-client in repository.
    Session committed successfully.
    ...
    Keystore created
    Key pair generated
    Certificate exported.
  7. Change the owner of the generated certificate file to the opc user.
    exit
    sudo chown opc:opc /tmp/orakey.cert
  8. Download the certificate file as the opc user.
    scp -i <path_to_private_key> opc@<node_public_ip>:/tmp/orakey.cert .

Update the Confidential Application for the Web Services Client

Import the Oracle Web Services Manager certificate into the domain's confidential application found in Oracle Identity Cloud Service.

  1. Access the Oracle Identity Cloud Service console.
  2. From the navigation menu, click Applications.
  3. Click the confidential application that was created for your client domain.
  4. Click the Configuration tab.
  5. Under Client Configuration, select Trusted for Client Type.
  6. For Certificate, click Import.
  7. For Certificate Alias, enter a unique name.
    For example, orakey_oauthclient
  8. Select the file orakey.cert, and then click Import.
  9. Click Add Scope.
  10. Select the confidential application of the domain that is the web services provider, and then click Add.
  11. Click Save.

Test the Sample Web Service Client

If you deployed the sample client application, you can use it to quickly verify the OAuth integration between Oracle Web Services Manager and Oracle Identity Cloud Service.

  1. Use the load balancer to access the sample application on your client domain.
    https://<client_lb_public_ip>/oauth-client
  2. For Address, enter the URL of your web service provider.
    https://<provider_lb_public_ip>/<service_endpoint>

    For example:

    https://203.0.113.21/myapp/myservice
  3. For Scope, enter this value.
    https://<provider_lb_public_ip>:443external

    For example:

    https://203.0.113.21:443external
  4. Click the Test button.