Showing posts with label Oracle. Show all posts
Showing posts with label Oracle. Show all posts

Friday, 23 February 2018

Oracle Apex - Forcing Password Change in Custom Authentication

Introduction

If you've created you own authentication scheme in APEX, you may be aware that there's no mechanism to hook into that enforces a password change. Typically you might want your users to change password after 90 days, or if it's just been reset by an admin.

The example in this blog uses a redirect on a global page region to switch to the change password page. It's not a full authentication solution and assumes the following:-
  • You have a table called system_users
  • The table has a column called "expired" which is either '1' or '0'.
  • You have already created a change password page (in my example this is page 106).
  • Page 106 has a process to change your password and reset the "expired" flag.
  • You already have a working authentication and password change function.

Instructions

1 - Create a function to check if your user account is expired.

(My example below assumes you have a "system_users" table with a column called "expired". But it's only a simple example. Write something better!)

Function check_expired(p_app_user varchar2)
 RETURN NUMBER AS
 l_return NUMBER;
BEGIN
  BEGIN
    SELECT 1
    INTO   l_return
    FROM   system_users
    WHERE  expired = 1
    AND    upper(username) = upper(p_app_user));
  EXCEPTION
    WHEN no_data_found THEN
      l_return := 0;
  END;
  RETURN l_return;
END check_expired;



2 - Create an application item called "G_PASSWORD_EXPIRED" and ensure its scope is 'Global'.

3 - Create an application computation for this item, set the computation point to After Authetication and the type to 'PL/SQL Expression'.

The compution will be:-

  check_expired(:APP_USER);
Create an Application Compution for G_PASSWORD_EXPIRED


4 -  Create a global page and add a region called "Redirect".

5 - Set the region type to 'PL/SQL Dynamic Content' and add the following code:-

IF :G_PASSWORD_EXPIRED = 1 THEN
   APEX_UTIL.REDIRECT_URL('F?P=&APP_ID.:106:&APP_SESSION.::&DEBUG.');
END IF;

(NB. Page 106 is the change password page)

6 - Set the Server-side Condition to 'Current Page is NOT in comma delimited list', and list pages you don't want the redirect to be affected by.

(NB. This should be the login page, and the change password page.)

7 - On your change password page, ensure your ChangePassword process sets the G_PASSWORD_EXPIRED item to zero, or you will be stuck in a loop.





Change Password Page Should also Reset G_PASSWORD_EXPIRED

That's all you need... the global page adds a page redirect and no attempt to hack an alternative page allowed me to get around it.

Tuesday, 18 July 2017

VB - Deploying an Application using Oracle Data Access

Introduction

It's great when you get your application to run in Visual Studio, or even from the compiled files on your PC, but at some stage you're going to want to deploy or share it. This is where I ran into problems with Oracle drivers.

Oracle  Drivers

You set up your Oracle access in VB by selecting the DLL that came with your client software and adding it to the project resources. Here's what mine looked like in Visual Studio..

Assigning the Oracle library as a project resource.
Then add the following imports into your program module..

Imports Oracle.DataAccess.Client
Imports Oracle.DataAccess.Types


But, although you've set your resources correctly, the DLL location and version is likely to be different on other machines you deploy to. So you'll probably to get errors.

You can start to fix this by setting the Copy Local value to be True, and then the DLL file gets bundled into the release folder when you re-compile.

Set Copy Local
But while this might get your locally compiled version working, it's likely that other machines will still have problems with driver compatibility errors.

Typically you'll see something like this..

Oracle.DataAccess.Client.OracleConnection' threw an exception. ---> Oracle.DataAccess.Client.OracleException: The provider is not compatible with the version of Oracle client

Solution

Download the Instant Client Basic Lite files from Oracle and unzip it to your PC. Copy the following library DLL files and put it into the same deploy folder as your executable:-

oci.dll
ociw32.dll
Oracle.DataAccess.dll 
orannzsbb11.dll
oraocci11.dll
oraociicus11.dll
OraOps11w.dll

Hopefully that will get you going.

Friday, 7 July 2017

VB - Connecting to an Oracle Database without using a TNS Entry

Introduction

Connecting to an Oracle database isn't too much of a problem, there's examples everywhere on the web along the following lines..

Dim conn As New OracleConnection()
Dim connstr as String, dataSource as String, userId as String, password as String
dataSource = "dev10g"
userId = "jsmith"
password = "letmein"
connstr = "Data Source=" + dataSource + "; User Id=" + userId + "; Password=" + password + ";"
conn.ConnectionString = connstr
Try
  conn.Open()
Catch ex As Exception
  ' Database connection failed
  conn.Dispose() 'Dispose of the connection
  Exit Sub
End Try


This works ok, but it's not very portable unless everyone that wants to use it sets themselves a TNS entry called "dev10g" in their tnsnames.ora file.

What if we wanted to define the host and port number in the config, and then connect without using TNS?

Connecting to Oracle Directly

In practice all we need to do is alter the connection string to provide the information that the tnsnames.ora would have sent. So the code above doesnt change much.

Dim conn As New OracleConnection()
Dim connstr As String
Dim dbServer As String, dbPort As String, dbServiceName As String
Dim userId As String, password As String

dbServer = "lordv01"
dbPort = "1521"
dbServiceName = "dev10g"
userId = "jsmith"
password = "letmein"
dconnstr = "Data Source=" + dbServer + ":" + dbPort + "/" + dbServiceName + ";User ID=" + userId + ";Password=" + password
conn.ConnectionString = connstr
Try
  conn.Open()
  Catch ex As OracleException
  conn.Dispose() 'Dispose of the connection
  Exit Sub
End Try


It took me a bit of poking around to find the right syntax, so hopefully someone will find this useful.

Friday, 9 December 2016

A Simple Guide to Oracle Data Pump

Introduction

In order to create a test system for one of our customers I needed to copy some schemas from the live oracle database. As the main schema contained a lot of objects, I realised that the best thing to use was Data Pump. Something I'd never used it before.

Oracle Data Pump first appeared in 10g and provided a newer and more flexible alternative to the 'exp' and 'imp' utilities from previous Oracle versions. It's a server based technology so you'll need access to the file directory structure on the database server. That means you'll need to be able to remote connect to both source and target servers.

Running an Export

We're going to start by running a schema export, it's quite straight forward, but we need to ensure that we have a directory object configured in Oracle. You could go ahead and just add one, but it's worth looking to see if there's one already set up that you can use. Log into the source server (in my case Live) and type the following:-

SQL> select directory_name, directory_path from all_directories;

The results should give you a column listing the object name, and a second stating it's actual directory path on disk. It makes sense to choose one where the directory actually exists, and where you have file creations rights, but that should go without saying!

If nothing suitable exists then go ahead and create one, and then grant yourself read and write on it.

You run the export from the operating systems command prompt, here's what I used:-

expdp <my user>/<my password> directory=<my directory object> dumpfile=<my export file>.dmp schemas=<schema to export>

When it runs it will output process to the screen and may take a number of minutes to complete (depending on number of objects and size of tables). If you'd prefer the progress can be sent to a file just by including the following paramater:-

  logfile=<export log>.log

Now if you go to the directory listed in the directory_path you should see your DMP file waiting for you. They can be quite large but normally they zip quite well to make file transfer quicker.

Running an Import

The obvious next step was to copy the dump file over to the target server (in my case the new test system), but don't worry about where to put it just yet. What we need to do again is find an Oracle directory object to use for the import process.

I used the same query as before:-

SQL> select directory_name, directory_path from all_directories;

If a directory object exists then move your dump file into it, or (as before) create your own directory object in Oracle.

Before running the import we need to connect as sysdba and create the empty schema in the test system.


SQL> create user newschema identified by pwd4newschema;
 

(NB. The "Identified By" parameter is the password.)

Finally at the command prompt run the import command:-

impdp <my user>/<my password> DIRECTORY=<my directory object> DUMPFILE=<my export file>.dmp

Again the progress will be reported to the screen. Scan through it and check you don't get any errors. I had some dependancy issues because two other schemas referenced in the packaged functions where missing. If this happens to you, copy the missing references and recompile your packages.

Tuesday, 24 March 2015

Unicode data extracts using Oracle SQL*Plus in Unix

Introduction

The normal data spooling method using Oracle SQL*Plus will use the locale setting to determine the output file encoding method. Typically we are only interested in data extracts using just ASCII characters, but if you need (for example) to use a unicode character as a data separator, then things tend to go wrong.

Consider the following SQL statement which uses the double dagger unicode character as a separator:-

SELECT 'FIRST_NAME'||unistr('\2021')||'SURNAME' from dual;
 
If we run this in an SQLPlus session we get the following..

FIRST_NAMEĆ¢¡SURNAME 
 
(nb. I'm going to assume that you are using Putty as your terminal client)

 Setting your Locale in Putty

The data returned by the select looks like it's become mangled, but it's not. Your Putty session needs it's Window/Translation setting to be changed to UTF-8 before it can be displayed correctly.

Select UTF-8 translation in Putty


Now if we run this SQL again we get..

FIRST_NAME‡SURNAME

Similarly we can run the following SQL script using SQL*Plus to produce the file output.csv:-

set feedback off
set heading off
set term off
set echo off
spool output.csv SELECT 'FIRST_NAME'||unistr('\2021')||'SURNAME' from dual;
spool off
exit

The contents of output.csv will also display correctly using 'cat', but only because your locale settings in Putty are UTF-8.

NB. You can also copy the file back to your PC and open it using notepad (which handles UTF8 files correctly).

Scheduling with Cron

The spool script works OK when run interactively, but now let's schedule it from the cron. The script will be run using the machine's locale settings (probably ISO8859), and so SQLPlus will replace the unicode characters with question marks to keep it a valid ASCII format.

FIRST_NAME?SURNAME

But we can fix this by adding the following line near the start of our shell script:-

export NLS_LANG=.AL32UTF8