Following this guide
https://oracle-base.com/articles/misc/azure-ad-authentication-for-oracle-apex-applications#add-web-credentials
So running this
l_username varchar2(30) := 'APEX_210200';
begin
dbms_network_acl_admin.append_host_ace(
host => 'login.microsoftonline.com',
lower_port => 443,
ace => xs$ace_type(privilege_list => xs$name_list('connect'),
principal_name => l_username,
principal_type => xs_acl.ptype_db));
And then I try to test it with
l_json CLOB;
BEGIN
apex_web_service.g_request_headers( 1 ).name := 'User-Agent';
apex_web_service.g_request_headers( 1 ).value := 'Application Express';
l_json := apex_web_service.make_rest_request(
p_url => 'login.microsoftonline.com',
p_http_method => 'GET'
);
DBMS_OUTPUT.put_line('l_clob=' || l_json);
END;
But I get
ORA-06512: at "APEX_210200.WWV_FLOW_WEB_SERVICES", line 1182
ORA-06512: at "APEX_210200.WWV_FLOW_WEB_SERVICES", line 782
ORA-24247: network access denied by access control list (ACL)
But the web credentials + Authentication Schemes does work from within the APEX APP itself (logging into Azure and returning to the app)
Does my test fail because I'm running as sys?
Since I linked our Microsoft Active Directory with my Apex application using LDAP, I am trying to retrieve the groups for the user currently logged in from the Active Directory.
Here's the documentation: https://docs.oracle.com/cd/E59726_01/doc.50/e39149/apex_ldap.htm#AEAPI242
Here's my code of my dynamic action on page load, I am trying to retrieve a VARCHAR2 of all the groups the current user is part of, and to put it in a display-only field :
BEGIN
:P1_NEW := APEX_LDAP.MEMBER_OF2(
p_username => v('APP_USER'),
p_pass => 'mypassword',
p_auth_base => 'DOMAIN\',
p_host => 'XX.X.XXX.XX',
p_port => 389);
END;
But when I load my page, this error occurs
Ajax call returned server error ORA-31202: DBMS_LDAP : Erreur client/serveur LDAP : Invalid credentials. 80090308: LdapErr: DSID-0C090439, comment: AcceptSecurityContext error, data 52e, v4563 for Execute PL/SQL Code.
What's wrong in my code ? Thank you in advance for your help.
Thomas
I think you are using wrong the API Package APEX_LDAP. I am doing this on my own enviornment in a different way, but I am using Enterprise Edition:
Oracle Database version 19c
Oracle Apex version 20.1
Oracle Oracle Rest Data Services version 20.4
I have an authentication schema to make the login against the LDAP server of my own company. That authentication schema replaces the default one of Apex Locally managed users.
Application --> Shared Components --> Authentication Schemas --> Custom
function fn_val_user_pwd_ldap (
p_username in varchar2,
p_password in varchar2
)
return boolean
is
l_ldap_host varchar2(100) := 'myldaphost.com';
l_ldap_port number := 389 ;
begin
if APEX_LDAP.AUTHENTICATE(
p_username =>p_username,
p_password =>p_password,
p_search_base => 'OU=Users,OU=Mycompany,DC=de,DC=com,DC=corp',
p_host => l_ldap_host,
p_port => l_ldap_port)
then
dbms_application_info.set_action(null);
return true;
else
apex_util.set_authentication_result(p_code => 110);
apex_util.set_custom_auth_status(p_status => 'Username or password incorrect.');
dbms_application_info.set_action(null);
return false;
end if;
end;
Then, I have a post auth procedure in the same authentication method to retrieve the groups in LDAP. I prefer this way because it executes after the authentication, but you can do it also with a dynamic action.
declare
l_groups varchar2(4000);
BEGIN
l_groups := APEX_LDAP.MEMBER_OF2(
p_username => ':APP_USER',
p_pass => 'mypassword',
p_auth_base => 'OU=Users,OU=Mycompany,DC=de,DC=com,DC=corp',
p_host => 'myldaphost.com',
p_port => 389);
htp.p('Is Member of:'||l_groups);
END;
We don't use SSL to communicate internally with the LDAP Server, as this application is intranet. So the parameter p_use_ssl is by default to N.
As I was telling you in the comment section of your own question, I think the parameter p_auth_base refers to the LDIF format of your own LDAP server, not the domain name that refers to the AD.
UPDATE
Let me show you how it works. ( Of course, I hide sensitive information of my own company ). Sometimes it might happen that you can't get the group information as null. I am not sure here whether is a LDAP authorization issue rather than a problem with the APEX package itself
SQL> SET SERVEROUTPUT ON SIZE UNLIMITED ECHO ON
DECLARE
is_ok boolean;
l_mes varchar2(2000);
l_val varchar2(4000);
l_ldap_host varchar2(100) := 'myldapserver.com';
l_ldap_port number := 389 ;
BEGIN
if APEX_LDAP.AUTHENTICATE(
p_username =>'X329097',
p_password =>'********',
p_search_base => 'OU=Users,OU=Mycompany,DC=****,DC=*****,DC=****,DC=corp',
p_host => l_ldap_host,
p_port => l_ldap_port )
then
is_ok := true;
l_mes := 'Username and Password Correct' ;
dbms_output.put_line(l_mes);
else
l_mes := 'Username and Password Invalid' ;
dbms_output.put_line(l_mes);
end if;
if is_ok
then
l_val := APEX_LDAP.MEMBER_OF2(
p_username => 'X329097',
p_pass => '*********',
p_auth_base => 'OU=Users,OU=Mycompany,DC=****,DC=*****,DC=****,DC=corp',
p_host => l_ldap_host,
p_port => l_ldap_port);
dbms_output.put_line(l_val);
end if;
END;
/
Username and Password Correct
SC_APEX_ADMIN:SC_ORACLE_ADMIN
PL/SQL procedure successfully completed.
I tried to add your function and I cannot access to my application from my Login Page anymore. I've tried on the SQL Commands, here's what I got
DECLARE
VAL BOOLEAN;
BEGIN
IF APEX_LDAP.AUTHENTICATE(
p_username => 'thomas.tirole',
p_password => 'mypassword',
p_search_base => 'OU=Users,OU=Domain,DC=domain,DC=ch',
p_host => 'xx.x.xxx.xx',
p_port => 389
) THEN
dbms_output.put_line('AUTENTHICATED');
ELSE
DBMS_OUTPUT.PUT_LINE('NOT AUTHENTICATED');
END IF;
END;
---------------------------------------
NOT AUTHENTICATED
Statement processed.
0.00 seconds
If i try to do the MEMBER_OF2 function on the SQL Command, here's what I got :
declare
l_groups varchar2(4000);
BEGIN
l_groups := APEX_LDAP.MEMBER_OF2(
p_username => 'thomas.tirole',
p_pass => 'mypassword',
p_auth_base => 'OU=Users,OU=Domain,DC=domain,DC=ch', -- SAME WITH DOMAIN\
p_host => 'xx.x.xxx.xx',
p_port => 389);
htp.p('Is Member of:'||l_groups);
END;
---------------------------------------
ORA-31202: DBMS_LDAP : Erreur client/serveur LDAP : Invalid credentials. 80090308: LdapErr: DSID-0C090439, comment: AcceptSecurityContext error, data 52e, v4563
ORA-06512: à "APEX_210100.WWV_FLOW_LDAP", ligne 508
ORA-06512: à "SYS.DBMS_SYS_ERROR", ligne 86
ORA-06512: à "SYS.DBMS_LDAP", ligne 1487
ORA-06512: à "SYS.DBMS_LDAP", ligne 79
ORA-06512: à "APEX_210100.WWV_FLOW_LDAP", ligne 85
ORA-06512: à "APEX_210100.WWV_FLOW_LDAP", ligne 172
ORA-06512: à "APEX_210100.WWV_FLOW_LDAP", ligne 214
ORA-06512: à "APEX_210100.WWV_FLOW_LDAP", ligne 235
ORA-06512: à "APEX_210100.WWV_FLOW_LDAP", ligne 464
ORA-06512: à "APEX_210100.WWV_FLOW_LDAP", ligne 523
ORA-06512: à ligne 4
ORA-06512: à "SYS.DBMS_SQL", ligne 1721
I am working with a temporary Oracle Cloud account. What I thought was identical functionality works on the Apex Web Service, but not with UTL_HTTP. So this snippet works and returns the issue we are looking for.
DECLARE
L_json_response varchar2(32767);
BEGIN
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).Value := 'application/json';
L_json_response := apex_web_service.make_rest_request ( p_url =>
'https://mycompany.atlassian.net/rest/api/3/issue/BLABLA-23862', p_http_method => 'GET',
p_username => 'My.Username#mycompany', p_password => 'osBJWHhPasdffNVOQ5AA11D5'); -- Password is my Jira API Token
EXCEPTION WHEN OTHERS THEN raise_application_error(-20001,'An error was encountered -
'||SQLCODE||' -ERROR- '||SQLERRM);
END;
I can't use the Apex web service in the end product, and we need to use UTL_HTTP. This snippet should from my understanding do the same:
DECLARE
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'https://mycompany.atlassian.net/rest/api/3/issue/BLABLA-23862';
buffer varchar2(4000);
BEGIN
req := utl_http.begin_request(url, 'GET');
utl_http.set_header(req, 'Content-Type', 'application/json');
utl_http.set_header(req, 'Authorization', 'Basic ' || utl_encode.base64_encode('my.msername#mycompany:osBJWHhPasdffNVOQ5AA11D5'));
res := utl_http.get_response(req);
utl_http.read_text(res, buffer);
END;
But returns:
ORA-29273: HTTP request failed
ORA-29024: Certificate validation failure
ORA-06512: at "SYS.UTL_HTTP", line 639
ORA-06512: at "SYS.UTL_HTTP", line 1415 ORA-06512...
The key is the UTL_HTTP.SET_WALLET('');. You need to set the wallet(with empty string parameter) before initial http request.
The following code snippet tested with in Oracle Cloud ATP (Autonomous Transition Processing) database:
Setup network ACL
BEGIN
DBMS_NETWORK_ACL_ADMIN.CREATE_ACL(acl => 'my_acl.xml',
description => 'ACL for http request.',
principal => 'MY_USER',
is_grant => true,
privilege => 'connect');
DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE(acl => 'my_acl.xml',
principal => 'MY_USER',
is_grant => true,
privilege => 'resolve');
DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL(acl => 'my_acl.xml', host => 'www.oracle.com');
END;
Test https request
DECLARE
l_text VARCHAR2(32767);
BEGIN
UTL_HTTP.SET_WALLET('');
l_text := UTL_HTTP.REQUEST('https://www.oracle.com/index.html');
dbms_output.put_line(l_text);
END;
See official document and example (on the bottom of page):
In a way #OldProgrammer answered this the comment from 29-12-2020m but I don't know how to attribute the answer.
I needed to either couple the UTL_HTTP code to default wallet or create a new one. APEX_WEB_SERVICE probably does this implicitly while UTL_HTTP has to have it spelled out.
My question was for Oracle Cloud and I couldn't make the toolchain from OldProgrammers link work in Oracle Cloud. Rolled out a VM and it works.
Im trying to make a REST API call from db and for that i have tried to create a ACL first.Below are the query,I tried to execute via sysdba user.Im getting error.
Can someone help me.
BEGIN
DBMS_NETWORK_ACL_ADMIN.create_acl (
acl => 'test_sx_acl_file.xml',
description => 'A test of the ACL functionality',
principal => 'node',
is_grant => TRUE,
privilege => 'connect',
start_date => SYSTIMESTAMP,
end_date => NULL);
end;
/
PL/SQL procedure successfully completed.
2)
BEGIN
DBMS_NETWORK_ACL_ADMIN.assign_acl ( acl => 'test_sx_acl_file.xml ', host => '*.testapi.com', lower_port => NULL, upper_port => NULL);
END;
/
ERROR at line 1:
ORA-46059: Invalid ACL identifier specified
ORA-06512: at "SYS.DBMS_NETWORK_ACL_ADMIN", line 70
ORA-06512: at "SYS.DBMS_NETWORK_ACL_ADMIN", line 484
ORA-06512: at line 2
Why is that? what could be the reason
I need help with this code, I am getting an error saying following.
ORA-29273: HTTP request failed
ORA-12541: TNS:no listener
ORA-06512: at "SYS.UTL_HTTP", line 368
ORA-06512: at "SYS.UTL_HTTP", line 1118
ORA-06512: at line 5
29273. 00000 - "HTTP request failed"
*Cause: The UTL_HTTP package failed to execute the HTTP request.
*Action: Use get_detailed_sqlerrm to check the detailed error message.
Fix the error and retry the HTTP request.
I contacted network team and they see bidirectional traffic on that port being done, so I am not sure what else is/could be wrong? any ideas?
create or replace
procedure Test_Rest_Call3
is
req utl_http.req;
res utl_http.resp;
url varchar2(4000) := 'http://ipaddresshere:9099/api/batchProcess/1';
name varchar2(4000);
buffer varchar2(4000);
content varchar2(4000) := '';
begin
req := utl_http.begin_request(url, 'DELETE',' HTTP/1.1');
utl_http.set_header(req, 'user-agent', 'mozilla/4.0');
utl_http.set_header(req, 'content-type', 'application/json');
utl_http.set_header(req, 'Content-Length', length(content));
utl_http.write_text(req, content);
res := utl_http.get_response(req);
-- process the response from the HTTP call
begin
loop
utl_http.read_line(res, buffer);
dbms_output.put_line(buffer);
end loop;
utl_http.end_response(res);
exception
when utl_http.end_of_body
then
utl_http.end_response(res);
end;
end Test_Rest_Call3;
Have you checked if DBA granted to execute utl_http?
Just try to run it to be sure:
select utl_http.request('http://ipaddresshere:9099/api/batchProcess/1') from dual;
If you get error then ask DBA to give the permission accordingly:
grant execute on utl_http to your_oracle_user_name
grant execute on dbms_lock to user_name
BEGIN
DBMS_NETWORK_ACL_ADMIN.create_acl (
acl => 'local_sx_acl_file.xml',
description => 'A test of the ACL functionality',
principal => 'put your user_name',
is_grant => TRUE,
privilege => 'connect',
start_date => SYSTIMESTAMP,
end_date => NULL);
end;
begin
DBMS_NETWORK_ACL_ADMIN.assign_acl (
acl => 'local_sx_acl_file.xml',
host => 'localhost',
lower_port => 9002,
upper_port => NULL);
end;
I hope it will help.
Cheers,
Morteza Fakoorrad