Note:

Deploy App Gateway with Oracle Analytics Server on OCI Identity and Access Management Domains for Single Sign-On

Introduction

If you want to implement Single Sign-on (SSO) for Oracle Analytics Server on-premises using Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) Domains, we recommend to set up the App Gateway for SSO with IAM Domains for Oracle Analytics Server application. This set up will enable users to use their IAM Domain credentials and log in to the Oracle Analytics Server application.

Key Benefits

Objectives

Implement SSO for accessing the Enterprise Oracle Analytics Server and learn how to deploy the App Gateway docker image for SSO with IAM.

Prerequisites

  1. Oracle Apps Premium SKU for IAM Domains.

  2. Admin account for the IAM Domain.

  3. A machine to run the App Gateway.

  4. Oracle Analytics Server Application. If you do not have Oracle Analytics Server application, you can create one using the Marketplace Image, see Deploy Oracle Analytics Server on Oracle Cloud.

Task 1: Create an Enterprise Application in IAM Domain

You can create an Enterprise Application in IAM Domain using two approaches:

Approach 1: Create the Enterprise Application manually via Console

  1. Register the Enterprise Application in the IAM Domain. This will represent your Oracle Analytics Server application. Provide the necessary detail to register the application in IAM Domain and edit the SSO configuration. You can add the default resource to allow the access to all resources, else you can add each resources manually to get access to specific resources. Also, you can check the Configure SSO with Oracle Identity Cloud Service and App Gateway to know about the resources to add.

    Image 4

    Default Resource: /.*

    Image 1

    Check the box for Allow CORS, Require secure cookies and Add managed resources.

    Image 3

  2. Add the resources to the Authentication Policy. Add the default resource to cover all the resources. While adding it for authentication policy, remember to add the header for as iv-user and map it to the User Name.

    Image 2

Approach 2: Create the Enterprise Application via Python code

  1. Create a confidential application and retrieve client ID and client secret, which can then be used to perform a REST API call to OCI IAM for retrieving Access Token and subsequent API endpoints, see Oracle Identity Cloud Service: First REST API Call.

  2. Set up the config file on your local machine. The config.json file has information about the Identity Domain URL, Client ID and Client Secret which is used to generate the Access Token.

    {
    "iamurl"         : "https://idcs-###########.identity.oraclecloud.com",
    "client_id"      : "#######################",
    "client_secret"  : "#######################"
    }
    
  3. Generate the Access Token, which can be used to make further REST API calls to the OCI IAM endpoints.

    In the below code snippet, the function _get_encoded_ takes in Client ID and Client Secret as arguments and returns the base64-encoded string. This encoded string is further passed as an argument to the function get_access_token as an Authorization header, to obtain the Access Token by performing a POST request.

    #get base64 encoded
    def get_encoded(self,clid, clsecret):
        encoded = clid + ":" + clsecret
        baseencoded = base64.urlsafe_b64encode(encoded.encode('UTF-8')).decode('ascii')
        return baseencoded
    
    #get access token
    def get_access_token(self,url, header):
        para = "grant_type=client_credentials&scope=urn:opc:idm:__myscopes__"
        response = requests.post(url, headers=header, data=para, verify=False)
        jsonresp = json.loads(response.content)
        access_token = jsonresp.get('access_token')
        return access_token
    
    #print access token
    def printaccesstoken(self):
        obj = IAM()
        encodedtoken = obj.get_encoded(clientID, clientSecret)
        extra = "/oauth2/v1/token"
        headers = {'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
                'Authorization': 'Basic %s' % encodedtoken, 'Accept': '*/*'}
        accesstoken = obj.get_access_token(idcsURL + extra, headers)
        return accesstoken
    
  4. Create Enterprise application in IAM domain using the below Python code snippet.

    def createapplication(self):
        global clID
        global appID
        global resID1
        obj = IAM()
        obj.searchapps()
        accesstoken = obj.printaccesstoken()
        extra = "/admin/v1/Apps"
        headers = {'Accept': '*/*', 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + accesstoken}
        para = json.dumps({
        "schemas": [
            "urn:ietf:params:scim:schemas:oracle:idcs:App",
            "urn:ietf:params:scim:schemas:oracle:idcs:extension:samlServiceProvider:App",
            "urn:ietf:params:scim:schemas:oracle:idcs:extension:requestable:App",
            "urn:ietf:params:scim:schemas:oracle:idcs:extension:managedapp:App",
            "urn:ietf:params:scim:schemas:oracle:idcs:extension:webTierPolicy:App"
        ],
        "displayName": "OAS Enterprise App",
        "description": "New Enterprise Application for OAS",
        "landingPageURL": "http://150.xx.xx.xx:9502/analytics",
        "basedOnTemplate": {
            "value": "CustomEnterpriseAppTemplateId"
        },
        "isSamlServiceProvider": False,
        "isOAuthResource": False,
        "isOAuthClient": False,
        "showInMyApps": False,
        "isWebTierPolicy": False,
        "active": True,
        "isEnterpriseApp": True,
        "urn:ietf:params:scim:schemas:oracle:idcs:extension:requestable:App": {
        "requestable": False
        },
        "urn:ietf:params:scim:schemas:oracle:idcs:extension:webTierPolicy:App": {
        "webTierPolicyAZControl": "local"
        }
        })
        resp = requests.post(idcsURL + extra, headers=headers, verify=False, data=para)
        jsonresp = json.loads(resp.content)
        clID = jsonresp.get("name")
        #clSecret = jsonresp.get("clientSecret")
        appID = jsonresp.get("id")
        print("OAS Enterprise Application created with Client ID")
        print(clID)
        print("App ID of the created OAS Enterprise Application is :")
        print(appID)
    
        extra1 = "/admin/v1/AppResources"
        extra5 = "/admin/v1/Apps/"+appID
        headers1 = {'Accept': '*/*', 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + accesstoken}
    
        data= pd.read_csv("AppResourse.csv",delimiter=',')
        x=0  # For Reading the Data from the CSV file
        i=1  # For Providing the sequence vaule to the Web Policy
    
    ### This part of the code reads the data from CSV file adds the AppResource to the Enterprise application and also adds the Web Policy for all the added resources###
    
        for line in data.iterrows() :
            AppRsUrl=data.AppResourseURL[x] ## Take Application Resource URL as input from CSV file at xth Location
            ##print(AppRsUrl)
            metD=data.accessMode[x] ## Take Access method for Application Resource URL as input from CSV file at xth Location
            ResName=data.ResourceName[x] ## Take Application Resource Name as input from CSV file at xth Location
            para1 = json.dumps({
            "schemas": [
            "urn:ietf:params:scim:schemas:oracle:idcs:AppResource"
            ],
            "name": ResName,
            "resourceURL": AppRsUrl,
            "isRegex": True,
            "description": "OAS App Resourse",
            "app": {
                "value": appID
                }
            })
            resp1 = requests.request("POST",idcsURL + extra1, headers=headers1, verify=False, data=para1)
            ##print(resp1)
            jsonresp1 = json.loads(resp1.content)
            ##print(jsonresp1)
            resID1= jsonresp1.get("id")
            print("Resourse Added to the OAS Enterprise Application with ID")
            print(resID1)
    
            para3 = json.dumps({
            "schemas":[
            "urn:ietf:params:scim:api:messages:2.0:PatchOp"
            ],
            "Operations":[
            {
            "op":"add",
            "path":"urn:ietf:params:scim:schemas:oracle:idcs:extension:enterpriseApp:App:appResources",
            "value":[
                {
                "value":resID1
                }
            ]}]})
    
            resp3 = requests.request("PATCH",idcsURL + extra5, headers=headers1, verify=False, data=para3)
            # print(resp3)
            # jsonresp3 = json.loads(resp3.content)
            # print(jsonresp3)
    
    ### Based on the Access Mode the Web Policy will be generated###
    
            if metD=="oauth":
                jsonBody= "{\"filter\":\""+AppRsUrl+"\",\"headers\":[{\"iv-user\":\"$subject.user.userName\"}],\"comment\":\"abc\",\"resourceRefId\": \""+resID1+"\",\"resourceRefName\":\""+ResName+"\",\"type\":\"regex\",\"sequence\":\""+str(i)+"\",\"method\":\"oauth\"}"+","
            else:
                jsonBody= "{\"filter\":\""+AppRsUrl+"\",\"comment\":\"abc\",\"resourceRefId\": \""+resID1+"\",\"resourceRefName\":\""+ResName+"\",\"type\":\"regex\",\"sequence\":\""+str(i)+"\",\"method\":\"public\"}"+","
            ##print(jsonBody)
            x=x+1
            i=i+1
    
            with open('data.json', 'a') as f:
                json.dump(jsonBody, f)
    
    ## construct the payload for webtier and send it as a Json Body to the REST call###
    
        with open('data.json', 'r') as file: ## Temp json file to hold the payload before getting formated
            data = file.read()
            data1=data.replace('""','')
            ##print(data1)
        with open('formatedData.json', 'a') as file1: ## Actual json file to hoad the payload for the REST call to PATCH WebPolicy
            file1.writelines('{ \n')
            file1.writelines('"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],\n')
            file1.writelines('"Operations": [\n')
            file1.writelines('{"op": "add",\n')
            file1.writelines('"path": "urn:ietf:params:scim:schemas:oracle:idcs:extension:webTierPolicy:App:webTierPolicyJson",\n')
            file1.writelines(R'"value":"{\"cloudgatePolicy\":{\"version\":\"2.6\",\"requireSecureCookies\":true,\"allowCors\":true,\"disableAuthorize\":true,\"webtierPolicy\":[{\"policyName\":\"default\",\"comment\":\"Webtier policy\",\"resourceFilters\":[')
            data2=re.sub(r'.', '', data1, count = 1)
            data3=data2.rstrip(data2[-1])
            data4=data3.rstrip(data3[-1])
            file1.write(data4)
            file1.write(']}]}}"}]}')
            os.remove("data.json")
    
    ### REST API Call to PATCH the Web Policy to the created Enterprise Application###
    
        extra2 = "/admin/v1/Apps/"+appID
        headers2 = {'Accept': '*/*', 'Content-Type': 'application/scim+json', 'Authorization': 'Bearer ' + accesstoken}
        param = {'attributes': "urn:ietf:params:scim:schemas:oracle:idcs:extension:webTierPolicy:App:webTierPolicyJson,urn:ietf:params:scim:schemas:oracle:idcs:extension:webTierPolicy:App:webTierPolicyAZControl,urn:ietf:params:scim:schemas:oracle:idcs:extension:webTierPolicy:App:resourceRef"}
        webPolicy = json.load(open('formatedData.json'))
        payload = json.dumps(webPolicy)
        resp7 = requests.request("PATCH",idcsURL + extra2, headers=headers2, verify=False, data=payload, params=param)
        jsonresp7 = json.loads(resp7.content)
        ##print(resp7)
        ##print(jsonresp7)
        print("The OAS Enterprise Application has been PATCH with the WebPolicy for all the added Resources")
        os.remove("formatedData.json")
    
    
  5. You will need a csv file containing all the resources to be created using the above code snippet. Here is the link to the resource AppResources.csv.

Note: Make sure you have Python 3.x installed on your system and urllib3, requests and pandas Python packages installed as well to use the above code snippet. Also, the above code snippet is for reference purpose only and you can also build your own logic to achieve the same.

Task 2: Create App Gateway in IAM Domain

  1. Create the App Gateway on the IAM Domain under Security tab. Provide the necessary details to complete the configuration. Details needed to register the App Gateway are Name of the App Gateway and Host, which is the Public IP of the machine where you want to deploy the App Gateway image. Select the SSL enabled check box and add the certificate in the Additional Properties section that you are going to use for App Gateway in below format. Add correct path of the certificate on the App Gateway.

    ssl_certificate /usr/local/nginx/conf/server.crt;
    ssl_certificate_key /usr/local/nginx/conf/server.key;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!MD5;
    

    Image 7

    Note: You can use the public SSL certificate for above step and if you do not have any public certificate then you can use the self signed certificate as well. You can generate the self signed certificate with the following openSSL command.

    openssl req -x509 -newkey rsa:4096 -keyout /home/opc/certs/key.pem -out /home/opc/certs/cert.pem -sha256 -days 3650 -nodes -subj "/C=US/ST=Florida/L=Miami/O=Oracle/OU=Cloud/CN=oracle"
    
  2. Add the Enterprise application on the App Gateway we have registered in the first step as Apps. Choose the Enterprise app you created under Application, select Host under the Select a Host. Provide the Resource Prefix as / and under Origin Server provide the URL for your Oracle Analytics Server and Save the changes.

    Image 8

Task 3: Deploy the App Gateway Docker Image

  1. Download the App Gateway docker image. In IAM Domain, on the left hand side menu, click Settings, and then click Downloads. Download the App Gateway Docker Image for Identity Cloud Service and the App Gateway Wallet tool. Keep the App Gateway Docker Image and Wallet tool in separate directories. For example: /home/opc/appgateway for App Gateway and /home/opc/cwallet for Wallet tool.

  2. Create a wallet file containing the Client ID and Client Secret of the App Gateway that was created in the IAM Domain. Use the following steps to create the wallet file.

    env LD_LIBRARY_PATH=./lib ./cgwallettool --create -i **ClientID of AppGateway in IAM Domain**.
    
    

    Note: Upon executing the above, it will ask for Client Secret of App Gateway. These steps will create the cwallet.sso file for App Gateway.

    Image 9

  3. Install the Docker on the Machine for App Gateway using the following commands.

    sudo yum-config-manager --disable ol7_UEKR3 ol7_UEKR4
    sudo yum-config-manager --enable ol7_UEKR5
    sudo yum-config-manager --enable ol7_addons
    sudo yum install docker-engine docker-cli -y
    sudo systemctl enable --now docker
    sudo systemctl status docker
    sudo docker info
    sudo usermod -a -G docker $USER
    

    Note: We have used Oracle Linux 7 for configuring the docker image of App Gateway.

  4. You can use the certificate from any trusted public certificate authority or create the self-signed certificate as well using openSSL. Self-signed certificate example is as below:

    openssl req -x509 -newkey rsa:4096 -keyout /home/opc/certs/key.pem -out /home/opc/certs/cert.pem -sha256 -days 3650 -nodes -subj "/C=US/ST=Florida/L=Miami/O=Oracle/OU=Cloud/CN=oracle"
    
  5. As the docker image is in tar.gz format, we need to extract the image to create the docker container with the following step. Load the tar.gz file to the local Docker registry using following command:

    $ docker load -i **filename.tar.gz**
    

Task 4: Create App Gateway ENV file

  1. To run the App Gateway Docker container, the following environment variables must be set in the appgateway-env file. CG_APP_TENANT=<tenant name> IDCS_INSTANCE_URL=<idcs instance url>. The URL required to access the Identity Cloud Service instance. NGINX_DNS_RESOLVER=<resolver ip>.

    Note Do the nslookup of the IAM Domain URL and the server IP will be the value you need.

  2. Run the Docker using following command.

    sudo docker run -it -p 4443:4443 --name appgateway --env-file /home/opc/AppgwDocker/appgateway-env --env HOST_MACHINE=`hostname -f` --volume /home/opc/cwallet.sso:/usr/local/nginx/conf/cwallet.sso --volume /home/opc/server.key:/usr/local/nginx/conf/server.key --volume /home/opc/server.crt:/usr/local/nginx/conf/server.crt --net=host idcs/idcs-appgateway:23.2.92-2301160723
    
  3. Restart the docker using below commands:

    docker stop conatiner_ID
    docker start conatiner_ID
    

Task 5: Create Identity asserter on the Oracle Analytics Server WebLogic server

  1. Log in as admin to the WebLogic server admin console.

  2. Navigate to to the myrealm and to Providers. Create the OAMIdentityAsserter as a provider.

    Image 10

  3. After creating the Provider, edit the same to change the Control Flag to Required and then choose the Active types as iv-user.

    Image 11

  4. Set the iv-user in Provider Specific properties under SSOHeader Name and click Save.

    Image 12

  5. Reorder the providers list and keep the newly created provider on top.

  6. Restart the WebLogic server using script as below.

    sudo su oracle
    cd /u01/data/domains/bi/bitools/bin
    ./stop.sh
    ./start.sh
    
  7. Once the server is up again, you are ready to test the SSO.

Task 6: Test the SSO

Test the SSO by accessing the App Gateway URL https://AppGateway.example.com:4443/analytics, it will redirect the user to the OCI IAM Identity Domain for authentication and after successful authentication, user will get access to Oracle Analytics Server based on their role.

Note: AppGateway.example.com is for reference here, use correct URL as per your environment and make sure you have the correct DNS routing for it.

Acknowledgments

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.