Oracle REST Data Services (ORDS) 安全认证机制

前端之家收集整理的这篇文章主要介绍了Oracle REST Data Services (ORDS) 安全认证机制前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

HTTP or HTTPS

By default,the OAuth2 protocol requires all calls to be performed using HTTPS. You can read how to configure Apache Tomcat to enable HTTPShere.

For test purposes,you may want to configure ORDS to allow OAuth over HTTP. Edit the "/u01/ords/conf/ords/defaults.xml",adding the following entry.

<entry key="security.verifySSL">false</entry>

Restart Tomcat for the change to take effect.

$CATALINA_HOME/bin/shutdown.sh
$CATALINA_HOME/bin/startup.sh

Create a Test Database User

We need a new database user for our testing.

CONN / AS SYSDBA
ALTER SESSION SET CONTAINER=pdb1;

DROP USER testuser1 CASCADE;
CREATE USER testuser1 IDENTIFIED BY testuser1
  DEFAULT TABLESPACE users QUOTA UNLIMITED ON users;
  
GRANT CREATE SESSION,CREATE TABLE TO testuser1;

Create and populate a copy of the EMP table.

CONN testuser1/testuser1@pdb1

CREATE TABLE EMP (
  EMPNO NUMBER(4,0),ENAME VARCHAR2(10 BYTE),JOB VARCHAR2(9 BYTE),MGR NUMBER(4,HIREDATE DATE,SAL NUMBER(7,2),COMM NUMBER(7,DEPTNO NUMBER(2,CONSTRAINT PK_EMP PRIMARY KEY (EMPNO)
  );
  
insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7369,'SMITH','CLERK',7902,to_date('17-DEC-80','DD-MON-RR'),800,null,20);
insert into EMP (EMPNO,DEPTNO) values (7499,'ALLEN','SALESMAN',7698,to_date('20-FEB-81',1600,300,30);
insert into EMP (EMPNO,DEPTNO) values (7521,'WARD',to_date('22-FEB-81',1250,500,DEPTNO) values (7566,'JONES','MANAGER',7839,to_date('02-APR-81',2975,DEPTNO) values (7654,'MARTIN',to_date('28-SEP-81',1400,DEPTNO) values (7698,'BLAKE',to_date('01-MAY-81',2850,DEPTNO) values (7782,'CLARK',to_date('09-JUN-81',2450,10);
insert into EMP (EMPNO,DEPTNO) values (7788,'SCOTT','ANALYST',7566,to_date('19-APR-87',3000,DEPTNO) values (7839,'KING','PRESIDENT',to_date('17-NOV-81',5000,DEPTNO) values (7844,'TURNER',to_date('08-SEP-81',1500,DEPTNO) values (7876,'ADAMS',7788,to_date('23-MAY-87',1100,DEPTNO) values (7900,'JAMES',to_date('03-DEC-81',950,DEPTNO) values (7902,'FORD',DEPTNO) values (7934,'MILLER',7782,to_date('23-JAN-82',1300,10);
commit;
Enable ORDS and Create a Web Service

Enable REST web services for the test schema. We could use any unique and legal URL mapping pattern for the schema,so it is not necessary to expose the schema name as we have done here.

CONN testuser1/testuser1@pdb1

BEGIN
  ORDS.enable_schema(
    p_enabled             => TRUE,p_schema              => 'TESTUSER1',p_url_mapping_type    => 'BASE_PATH',p_url_mapping_pattern => 'testuser1',p_auto_rest_auth      => FALSE
  );
    
  COMMIT;
END;
/

Define a basic web service we can use for the tests.

CONN testuser1/testuser1@pdb1

BEGIN
  ORDS.define_service(
    p_module_name    => 'testmodule1',p_base_path      => 'testmodule1/',p_pattern        => 'emp/:empno',p_method         => 'GET',p_source_type    => ORDS.source_type_query,p_source         => 'SELECT * FROM emp WHERE empno = :empno',p_items_per_page => 0);

  COMMIT;
END;
/

The web service will now be available from the following URLs without authentication.

http://ol7-121.localdomain:8080/ords/pdb1/testuser1/testmodule1/emp/7788
https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788

For the rest of the article I will assume HTTPS has been enabled. If you've enabled HTTP access to OAUTH,then simply change the test URLs accordingly for the tests. The "curl" command below uses the "-k" option to prevent the call from verifying the self-signed certificate used on this server. We can see the expected JSON data is returned.

$ curl -i -k https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed,29 Jun 2016 08:35:50 GMT

{"items":[{"empno":7788,"ename":"SCOTT","job":"ANALYST","mgr":7566,"hiredate":"1987-04-18T23:00:00Z","sal":3000,"comm":null,"deptno":20}]}
$

Now let's start setting up authentication.

ORDS Roles and Privileges

To protect the web service,we need to create a role with an associated privilege,then map the privilege to the web service. Normally,we would expect a role to be a collection of privileges,and of course a single privilege can be part of multiple roles,but in this case we will keep it simple. The following code creates a new role called "emp_role".

CONN testuser1/testuser1@pdb1

BEGIN
  ORDS.create_role(
    p_role_name => 'emp_role'
  );
  
  COMMIT;
END;
/


-- Display the role.
COLUMN name FORMAT A20

SELECT id,name
FROM   user_ords_roles
WHERE  name = 'emp_role';

        ID NAME
---------- --------------------
     10312 emp_role

SQL>

We create a new privilege called "emp_priv",which is associated with the role.

CONN testuser1/testuser1@pdb1

DECLARE
  l_arr OWA.vc_arr;
BEGIN
  l_arr(1) := 'emp_role';
  
  ORDS.define_privilege (
    p_privilege_name => 'emp_priv',p_roles          => l_arr,p_label          => 'EMP Data',p_description    => 'Allow access to the EMP data.'
  );
   
  COMMIT;
END;
/


-- Display the privilege.
COLUMN name FORMAT A20

SELECT id,name
FROM   user_ords_privileges
WHERE  name = 'emp_priv';

        ID NAME
---------- --------------------
     10313 emp_priv

SQL>


-- Display the privilege-role relationship.
COLUMN privilege_name FORMAT A20
COLUMN role_name FORMAT A20

SELECT privilege_id,privilege_name,role_id,role_name
FROM   user_ords_privilege_roles
WHERE  role_name = 'emp_role';

PRIVILEGE_ID PRIVILEGE_NAME          ROLE_ID ROLE_NAME
------------ -------------------- ---------- --------------------
       10313 emp_priv                  10312 emp_role

SQL>

BEGIN ORDS.create_privilege_mapping( p_privilege_name => 'emp_priv',p_pattern => '/testmodule1/emp/*' ); COMMIT; END; / -- Display mapping. COLUMN name FORMAT A20 COLUMN pattern FORMAT A20 SELECT privilege_id,name,pattern FROM user_ords_privilege_mappings WHERE name = 'emp_priv'; PRIVILEGE_ID NAME PATTERN ------------ -------------------- -------------------- 10246 emp_priv /testmodule1/emp/* SQL>

Once this mapping is in place,we can no longer access the web service without authentication. At this point we've not defined how we should authenticate,only that authentication is needed to access this resource.

$ curl -i -k https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Content-Type: text/html
Content-Length: 11577
Date: Wed,29 Jun 2016 08:45:32 GMT
.
. Edited out for brevity.
.
$
First-Party Authentication (Basic Authentication)

If you have to support basic authentication,it is possible by creating users on the ORDS server.

Create a new ORDS user called "emp_user" with access to the "emp_role" role.

$ cd /u01/ords
$ $JAVA_HOME/bin/java -jar ords.war user emp_user emp_role
Enter a password for user emp_user:
Confirm password for user emp_user:
Jun 29,2016 11:52:42 AM oracle.dbtools.standalone.ModifyUser execute
INFO: Created user: emp_user in file: /u01/ords/conf/ords/credentials
$ 

Access the web service from a browser using the following URL.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788

You are presented with a 401 message,which includes a "sign in" link. Click the link,sign in with the ORDS credentials you just created and you will be directed to web service output.

Alternatively,specify the credentials in a "curl" command.

$ curl -i -k --user emp_user:Password1 https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat,02 Jul 2016 06:19:47 GMT

{"items":[{"empno":7788,"deptno":20}]}
$
OAuth 2

There are several methods of authenticating to the web service using OAuth 2. Before starting each example,make sure you clean up the OAUTH metadata,as described in theDeleting OAUTH Metadatasection. You do not need to delete the web service itself or the ORDS role,privilege and URL mapping. Each authentication example assumes these are already in place.

OAuth 2 revolves around registering clients,which represent a person or an application wanting to access the resource,then associating those clients to roles. Once the client is authenticated,it has access to the protected resources associated with the roles.

Many of the parameters in calls to theOAUTHpackage are optional,but cause problems down the line if they are omitted. TheOAUTHpackage calls in the following examples are the simplest I could make them without causing failures. When calling theCREATE_CLIENTprocedure,theP_PRIVILEGE_NAMESparameter is mandatory,but it will accept dummy text if you don't want to associate a privilege directly to the client.

OAuth 2 : Client Credentials

The client credentials flow is a two-legged process that seems the most natural to me as I mostly deal with server-server communication,which should have no human interaction. For this flow we use the client credentials to return an access token,which is used to authenticate calls to protected resources. The example steps through the individual calls,but in reality it would be automated by the application.

Remember to clean up the OAUTH Metadata,183); text-decoration-line: none;" rel="nofollow">Deleting OAUTH Metadatasection.

Create a client with the grant type of "client_credentials".

CONN testuser1/testuser1@pdb1

BEGIN
  OAUTH.create_client(
    p_name            => 'Emp Client',p_grant_type      => 'client_credentials',p_owner           => 'My Company Limited',p_description     => 'A client for Emp management',p_support_email   => 'tim@example.com',p_privilege_names => 'emp_priv'
  );

  COMMIT;
END;
/

-- Display client details.
COLUMN name FORMAT A20

SELECT id,client_id,client_secret
FROM   user_ords_clients;

        ID NAME                 CLIENT_ID                        CLIENT_SECRET
---------- -------------------- -------------------------------- --------------------------------
     10316 Emp Client           3NvJRo_a0UwGKx7Q-kivtA..         F5WVwyrWxXj3ykmhSONldQ..

sql>


-- Display client-privilege relationship.
SELECT name,client_name
FROM   user_ords_client_privileges;

NAME                 CLIENT_NAME
-------------------- ------------------------------
emp_priv             Emp Client

sql>

Associate the client with the role that holds the correct privileges for the resources it needs to access.

BEGIN
  OAUTH.grant_client_role(
    p_client_name => 'Emp Client',p_role_name   => 'emp_role'
  );

  COMMIT;
END;
/


-- Display client-role relationship.
COLUMN client_name FORMAT A30
COLUMN role_name FORMAT A20

SELECT client_name,role_name
FROM   user_ords_client_roles;

CLIENT_NAME                    ROLE_NAME
------------------------------ --------------------
Emp Client                     emp_role

sql>

In order to access the web service,we must first retrieve an access token using theCLIENT_IDandCLIENT_SECRETwe queried from theUSER_ORDS_CLIENTSview.

CLIENT_ID     : 3NvJRo_a0UwGKx7Q-kivtA..
CLIENT_SECRET : F5WVwyrWxXj3ykmhSONldQ..
OAUTH URL     : https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/token

The example below retrieves the access token. Notice the user format of "CLIENT_ID:CLIENT_SECRET". It is easy to miss the ":" when you look at this for the first time.

$ curl -i -k --user 3NvJRo_a0UwGKx7Q-kivtA..:F5WVwyrWxXj3ykmhSONldQ.. --data "grant_type=client_credentials" https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/token
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed,29 Jun 2016 12:07:02 GMT

{"access_token":"-zYl-sFyB2iLicAHw2TsRA..","token_type":"bearer","expires_in":3600}
$

We can now use the access token to call our web service. Notice the "Authorization: Bearer {access-token}" entry in the header of the call.

$ curl -i -k -H"Authorization: Bearer -zYl-sFyB2iLicAHw2TsRA.." https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed,29 Jun 2016 12:07:31 GMT

{"items":[{"empno":7788,sans-serif; font-size: 16px;">We successfully accessed the protected web service.

OAuth 2 : Authorization Code

The authorization code flow is a three-egged process. The user accesses a URL in a browser,which prompts for credentials. Once authenticated,the browser is redirected to a specified page with an authhorization code as one of the parameters in the URL. That authorization code is used in a call to generate an access token,which is used to authenticate calls to protected resources. With the exception of the user confirmation,all the other steps in the flow should be handled by the application. All the steps will be presented separately in the example that follows.

Create a client using the grant type of "authorization_code". The redirect and support URLs are not real,but we will be able to follow the example through anyway.

Box-sizing: border-Box; overflow: auto; font-family: Menlo,p_grant_type      => 'authorization_code',p_redirect_uri    => 'https://ol7-121.localdomain:8443/ords/pdb1/testuser1/redirect',p_support_uri     => 'https://ol7-121.localdomain:8443/ords/pdb1/testuser1/support',p_privilege_names => 'emp_priv'
  );

  COMMIT;
END;
/


-- Display client details.
COLUMN name FORMAT A20

SELECT id,client_secret
FROM   user_ords_clients;

        ID NAME                 CLIENT_ID                        CLIENT_SECRET
---------- -------------------- -------------------------------- --------------------------------
     10333 Emp Client           gxqNSyxPbLUJhSj1yBe8qA..         E-_mKJBlOTfTdHc_zISniA..

sql>

We then attempt to request an authorization code. Notice we are using theCLIENT_IDfrom theUSER_ORDS_CLIENTSview along with a unique string that will represent the state.

CLIENT_ID     : gxqNSyxPbLUJhSj1yBe8qA..
State         : 3668D7A713E93372E0406A38A8C02171
URL           : https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=code&client_id={client_id}&state={state}

Access the following URL from a browser.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=code&client_id=gxqNSyxPbLUJhSj1yBe8qA..&state=3668D7A713E93372E0406A38A8C02171

Box-sizing: border-Box; margin-top: 0px; margin-bottom: 11px; font-family: "Helvetica Neue",sign in with the ORDS credentials you created ealier (emp_user) and you will be directed to an approval page. Click the "Approve" button,which will take you to the redirect page you specified for the client.

The redirect page we specified for the client doesn't really exist,but we can get the authorization code and state from the URL.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/redirect?code=FF-APuIMukuBlrver1XU2A..&state=3668D7A713E93372E0406A38A8C02171

The application should check the state string matches the one used in the initial call. We use the authorization code to retrieve the access token.

CLIENT_ID     : gxqNSyxPbLUJhSj1yBe8qA..
CLIENT_SECRET : E-_mKJBlOTfTdHc_zISniA..
User          : CLIENT_ID:CLIENT_SECRET
Data          : grant_type=authorization_code&code={authorization-code}
URL           : https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/token

The following call retrieves the access token.

$ curl -i -k --user gxqNSyxPbLUJhSj1yBe8qA..:E-_mKJBlOTfTdHc_zISniA.. --data "grant_type=authorization_code&code=FF-APuIMukuBlrver1XU2A.." https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/token
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed,29 Jun 2016 12:38:52 GMT

{"access_token":"cOYb2hFK_SyxOh8o9n6R7A..","expires_in":3600,"refresh_token":"RC33rvSwAfhguraOWlvgfA.."}
$

We can now access the protected resource using the access token.

$ curl -i -k -H"Authorization: Bearer cOYb2hFK_SyxOh8o9n6R7A.." https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed,29 Jun 2016 12:40:34 GMT

{"items":[{"empno":7788,"deptno":20}]}
$
OAuth 2 : Implicit

The implicit flow is a two-legged process that requires user interaction. The user accesses a URL in a browser,the browser is redirected to a specified page with an access token as one of the parameters in the URL. That access token is used to authenticate calls to protected resources. The example steps through the individual calls,but in reality everything but the user interaction would be automated by the application.

Create a client using the grant type of "implicit". The redirect and support URLs are not real,p_grant_type => 'implicit',client_secret FROM user_ords_clients; ID NAME CLIENT_ID CLIENT_SECRET ---------- -------------------- -------------------------------- -------------------------------- 10325 Emp Client 0docHbkL8__7Ic58n7GCBA.. sql>

We then attempt to request an access token. Notice we are using theCLIENT_ID : 0docHbkL8__7Ic58n7GCBA.. State : 3668D7A713E93372E0406A38A8C02171 URL : https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=code&client_id={client_id}&state={random-string}

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=token&client_id=0docHbkL8__7Ic58n7GCBA..&state=3668D7A713E93372E0406A38A8C02171

Box-sizing: border-Box; margin-top: 0px; margin-bottom: 11px; font-family: "Helvetica Neue",but we can get the access token from the URL.

https://ol7-121.localdomain:8443/ords/pdb1/testuser1/redirect#token_type=bearer&access_token=5SVR_NVP5N_OnDQt6iSxJg..&expires_in=3600&state=3668D7A713E93372E0406A38A8C02171

The application should check the state string matches the one used in the initial call. We can now access the protected resource using the access token.

$ curl -i -k -H"Authorization: Bearer 5SVR_NVP5N_OnDQt6iSxJg.." https://ol7-121.localdomain:8443/ords/pdb1/testuser1/testmodule1/emp/7788
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
ETag: "jtC17IXyetESUjSkxB2ani/a1TnFh28yfor+fLmxxUzGr6G9IFxQ77+/Gd71W4Qzz0rSxf90Qqbl+ICwezTayQ=="
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed,29 Jun 2016 12:15:35 GMT

{"items":[{"empno":7788,"deptno":20}]}
$
Deleting OAuth Metadata

We remove the OAuth Metadata for the client role mapping and the client using the following code. They could be combined as a single block,but I've left them separate so they can be run individually.

BEGIN
  OAUTH.revoke_client_role(
    p_client_name => 'Emp Client',p_role_name   => 'emp_role'
  );

  COMMIT;
END;
/

BEGIN
  OAUTH.delete_client(
    p_name => 'Emp Client'
  );

  COMMIT;
END;
/
Deleting ORDS Metadata

The ORDS URL mapping,privilege and roles are deleted using the following code. Once this is removed,the web service will be publicly available again.

BEGIN
  ORDS.delete_privilege_mapping(
    p_privilege_name => 'emp_priv',p_pattern => '/testmodule1/emp/*'
  );     

  COMMIT;
END;
/

BEGIN
  ORDS.delete_privilege (
    p_name => 'emp_priv'
  );
   
  COMMIT;
END;
/

BEGIN
  ORDS.delete_role(
    p_role_name => 'emp_role'
  );
  
  COMMIT;
END;
/

猜你在找的Oracle相关文章