Forum Stats

  • 3,853,631 Users
  • 2,264,247 Discussions
  • 7,905,419 Comments

Discussions

SSO authentication do not log out users correctly

Mohammas
Mohammas Member Posts: 31
edited May 27, 2019 8:27PM in APEX Discussions

Hi,

We are currently on Oracle 12.1.0.2.0 and Apex 5.1.4.

Set-up:

There are three applications.

1. SSO Application - This has homescreen with hyperlink to actual applications(Applications A & B).

2. Application A

3. Application B

Issue:

After the user logs out from any of the pages of above 3 applications, clicking on back button of browser, user is taken back to the exact same screen before logout.

Expected Behavior:

Once logged out, irrespective of what the user does, he should be directed to SSO login page, unless valid login credentials are provided.

Following is the code in our system,

Authentication Scheme:

SSO Application:

Name: SSO Login Authentication Scheme

Sentry Function_Name: sentry

Authentication Function Name: check_credentials

Session Not Valid:

URL: f?p=&APP_ID.:101:&SESSION.

Post Logout URL:

logout?p_app_alias=&APP_ALIAS.

Classic Navigation Bar Entry: Logout

Target -> URL -> logout?p_app_alias=&APP_ALIAS.

Application A & B:

Name: Auxiliary Authentication Scheme

Scheme Type: Custom

Sentry Function_Name: sentry

Session Not Valid:

login_page

Post Logout URL:

login_page

Classic Navigation Bar Entry: Logout

Target -> URL -> logout?p_app_alias=&APP_ALIAS.

CODE

Our code is very close to below article.

https://blogs.oracle.com/oraclemagazine/creating-custom-authentication

Sentry:

   FUNCTION sentry      RETURN BOOLEAN   AS      l_current_sid   NUMBER;      l_username      VARCHAR2 (240) := NULL;      l_cookie        OWA_COOKIE.cookie := OWA_COOKIE.get (c_cookie_name);   BEGIN      BEGIN         -- See if there is a leftover user cookie         l_username :=            UPPER (               wwv_flow_utilities.string_to_table2 (l_cookie.vals (1),                                                    sep   => '^') (1));      EXCEPTION         WHEN OTHERS         THEN            RETURN FALSE;      END;      l_current_sid := APEX_CUSTOM_AUTH.get_session_id_from_cookie;      -- If the apex session from the cookie is valid, re-instantiate the session      IF APEX_CUSTOM_AUTH.is_session_valid      THEN         wwv_flow.g_instance := l_current_sid;         IF l_username = APEX_CUSTOM_AUTH.get_username         THEN            APEX_CUSTOM_AUTH.define_user_session (               p_user         => l_username,               p_session_id   => l_current_sid);            RETURN TRUE;         ELSE            -- Username mismatch. Unset the session cookie and redirect back here to take other branch            APEX_CUSTOM_AUTH.LOGOUT (               p_this_app             => v ('APP_ID'),               p_next_app_page_sess   =>    v ('APP_ID')                                         || ':'                                         || NVL (v ('APP_PAGE_ID'), 0)                                         || ':'                                         || l_current_sid);            -- tell apex engine to stop processing and return false            wwv_flow.g_unrecoverable_error := TRUE;            RETURN FALSE;         END IF;      ELSE         -- application session cookie not valid; we need a new apex session         APEX_CUSTOM_AUTH.define_user_session (            p_user         => l_username,            p_session_id   => wwv_flow_custom_auth.get_next_session_id);         wwv_flow.g_unrecoverable_error := TRUE;  -- tell flows engine to quit         IF OWA_UTIL.get_cgi_env ('REQUEST_METHOD') = 'GET'         THEN            wwv_flow_custom_auth.remember_deep_link (               p_url   =>    'f?'                          || wwv_flow_utilities.get_cgi_query_string_decoded);         ELSE            wwv_flow_custom_auth.remember_deep_link (               p_url   =>    'f?p='                          || TO_CHAR (wwv_flow.g_flow_id)                          || ':'                          || TO_CHAR (NVL (wwv_flow.g_flow_step_id, 0))                          || ':'                          || TO_CHAR (wwv_flow.g_instance));         END IF;         -- register session in sessions$,set cookie,redirect back         APEX_CUSTOM_AUTH.post_login (            p_uname      => l_username,            p_app_page   =>    wwv_flow.g_flow_id                            || ':'                            || NVL (wwv_flow.g_flow_step_id, 0));         RETURN FALSE;      END IF;         EXCEPTION      WHEN OTHERS      THEN         logger.error (DBMS_UTILITY.format_error_backtrace);         logger.error (DBMS_UTILITY.format_call_stack);         RAISE;   END sentry;

Check Credentails:

C_Cookie_name value is "VALID_SESSION";

   FUNCTION check_credentials (p_username   IN VARCHAR2,                               p_password   IN VARCHAR2)      RETURN BOOLEAN   AS      l_result                BOOLEAN;   BEGIN      HTP.init;      OWA_UTIL.mime_header ('text/html', FALSE);      set_sso_cookie;   EXCEPTION      WHEN OTHERS      THEN         logger.error (DBMS_UTILITY.format_error_backtrace);         logger.error (DBMS_UTILITY.format_call_stack);         RAISE;   END check_credentials;      PROCEDURE set_sso_cookie   IS      --sets suite cookie, called from check_credentials only      l_t_id   NUMBER := NULL;   BEGIN      OWA_COOKIE.send (         name      => c_cookie_name,         VALUE     => UPPER (v ('P101_USERNAME')) || '^' || v ('APP_SESSION'),         expires   => NULL,         PATH      => '/');   EXCEPTION      WHEN OTHERS      THEN         logger.error (DBMS_UTILITY.format_error_backtrace);         logger.error (DBMS_UTILITY.format_call_stack);         RAISE;   END set_sso_cookie;

Login Page

   PROCEDURE login_page   AS   BEGIN      OWA_UTIL.redirect_url (logout_url);   EXCEPTION      WHEN OTHERS      THEN         logger.error (DBMS_UTILITY.format_error_backtrace);         logger.error (DBMS_UTILITY.format_call_stack);         RAISE;   END;      FUNCTION logout_url      RETURN VARCHAR2   AS      l_return                   VARCHAR2 (225);      l_host_port                VARCHAR2 (25);      l_service_name             VARCHAR2 (15);      c_sso_app_alias   CONSTANT VARCHAR2 (10) := 'SSO';   BEGIN      l_host_port := OWA_UTIL.get_cgi_env ('HTTP_HOST');      SELECT ords_serv_name        INTO l_service_name        FROM apex_usr.apex_applications       WHERE application_id = c_sso_app_alias;      l_return :=            'http://'         || l_host_port         || '/'         || l_service_name         || '/f?p='         || c_sso_app_alias         || ':LOGIN';      RETURN l_return;   EXCEPTION      WHEN OTHERS      THEN         logger.error (DBMS_UTILITY.format_error_backtrace);         logger.error (DBMS_UTILITY.format_call_stack);         RAISE;   END logout_url;

Logout

   PROCEDURE LOGOUT (p_app_alias IN VARCHAR2 DEFAULT NULL)   IS      l_sqlerrm                 VARCHAR2 (4000) DEFAULT NULL;      l_target_dad              VARCHAR2 (400) DEFAULT NULL;      l_target_instance         VARCHAR2 (400) DEFAULT NULL;      l_target_url              VARCHAR2 (4000) DEFAULT NULL;      l_target_app_alias        VARCHAR2 (4000) DEFAULT NULL;      l_target_app_id           NUMBER DEFAULT NULL;      l_target_logout_page_id   NUMBER DEFAULT NULL;      l_last_instance           VARCHAR2 (400) DEFAULT NULL;      l_last_url                VARCHAR2 (4000) DEFAULT NULL;      l_last_app_id             NUMBER DEFAULT NULL;      l_calling_app_id          NUMBER DEFAULT v ('APP_ID');      l_calling_app_alias       VARCHAR2 (400)                                   DEFAULT NVL (p_app_alias, v ('APP_ALIAS'));      l_calling_instance        VARCHAR2 (400) DEFAULT NULL;      l_script                  VARCHAR2 (400) DEFAULT '/apex';      l_host                    VARCHAR2 (400)                                   DEFAULT OWA_UTIL.get_cgi_env ('HTTP_HOST');      l_app_cnt                 NUMBER DEFAULT NULL;      l_logout_cnt              NUMBER := 0;      l_app_found               BOOLEAN := FALSE;      l_is_sso2                 NUMBER :=  0;      l_service_name            VARCHAR2 (15);   BEGIN      -- get instance info from apps table based on this iteration's invoking application alias      FOR appinfo IN (SELECT instance, id AS app_id                        FROM apex_usr.apex_applications                       WHERE application_id = l_calling_app_alias)      LOOP         l_calling_instance := appinfo.instance;         l_calling_app_id := appinfo.app_id;      END LOOP;      -- set through cursor of active apps to find the next one needing deauthentication      FOR i IN (  SELECT id           AS app_id,                         instance,                         host_port,                         logout_page_id,                         application_id AS app_alias                    FROM apex_usr.apex_applications                   WHERE active_flag = c_yes_value                ORDER BY instance, id)      LOOP         --deauthenticating all the apps         APEX_CUSTOM_AUTH.LOGOUT (p_this_app => i.app_id);         IF NOT l_app_found         THEN            l_last_instance := l_target_instance;            l_last_app_id := l_target_app_id;            l_target_instance := i.instance;            l_target_app_alias := i.app_alias;            l_target_app_id := i.app_id;            IF    (    l_last_instance = l_calling_instance                   AND NVL (l_last_app_id, -1) = NVL (l_calling_app_id, -1))               OR p_app_alias IS NULL            THEN               l_app_found := TRUE;            END IF;         END IF;      END LOOP;      -- expire the suite cookie if all apps have been deauthenticated      IF p_app_alias IS NULL      THEN         LOGOUT (p_app_alias => l_target_app_alias);         RETURN;      ELSE         expire_cookie;            APEX_CUSTOM_AUTH.logout_then_go_to_url (               p_args   => l_target_app_id || ':' || fhlb_logout_url);      END IF;      wwv_flow.g_unrecoverable_error := TRUE;   EXCEPTION      WHEN OTHERS      THEN         l_sqlerrm := SQLERRM;         logger.error (DBMS_UTILITY.format_error_backtrace);         logger.error (DBMS_UTILITY.format_call_stack);         RAISE;   END LOGOUT;      PROCEDURE expire_cookie   IS      l_t_id   NUMBER := NULL;   BEGIN      HTP.init;      OWA_UTIL.mime_header ('text/html', FALSE);      OWA_COOKIE.send (name      => c_cookie_name,                       VALUE     => 'user_logged_out',                       expires   => SYSDATE - 100,                       PATH      => '/');   EXCEPTION      WHEN OTHERS      THEN         logger.error (DBMS_UTILITY.format_error_backtrace);         logger.error (DBMS_UTILITY.format_call_stack);         RAISE;   END expire_cookie;

Let us know what we are missing, because of which the session is not expiring. Any inputs are highly appreciated.

Thanks,

Shoaib

Answers

  • Scott Wesley
    Scott Wesley Member Posts: 6,260 Gold Crown
    edited May 27, 2019 10:42AM

    I think you're using the standard Logout functionality. The URL needs to be modified to communicate with your authentication provider.

    Relevant discussion:

  • Mohammas
    Mohammas Member Posts: 31
    edited May 27, 2019 2:59PM

    Thanks for quick response Scott, I did read the articles shared by you and Jos Dols, but I am looking for a solution for Single Sign On Logout and the one that has been mentioned in those articles is of Social Sign On. Basically we have three apex applications, once the user logs out of one application, he should be logged out of all them. Please help me understand, if the URL suggested by you would work good for Single Sign On as well.

    Thanks,

    Shoaib

  • Scott Wesley
    Scott Wesley Member Posts: 6,260 Gold Crown
    edited May 27, 2019 8:27PM

    You need to determine the relevant URL for SSO.

    Social Sign On will have different logout URLs, depending on if you use Azure, Google, etc.

    So SSO will also have it's own URL to indicate the user has logged out.