Oracle REST Data Services (ORDS) 安全认证机制
HTTP or HTTPSBy 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 UserWe 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 PrivilegesTo 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 the OAuth 2 : Client CredentialsThe 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 the 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 https://ol7-121.localdomain:8443/ords/pdb1/testuser1/oauth/auth?response_type=token&client_id=0docHbkL8__7Ic58n7GCBA..&state=3668D7A713E93372E0406A38A8C02171 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; / (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |