Skip to content

EDB Postgres Advanced Server 9.5 new features – Profiles

The just released version of EDB Postgres Advanced Server 9.5 introduces profiles very much the same as in Oracle. Lets have a look at it.

As in Oracle there is a default profile:

(enterprisedb@[local]:5445) [postgres] > x
Expanded display is on.
(enterprisedb@[local]:5445) [postgres] > select * from edb_profile;
-[ RECORD 1 ]-----------+--------
prfname                 | default
prffailedloginattempts  | -2
prfpasswordlocktime     | -2
prfpasswordlifetime     | -2
prfpasswordgracetime    | -2
prfpasswordreusetime    | -2
prfpasswordreusemax     | -2
prfpasswordverifyfuncdb | NULL
prfpasswordverifyfunc   | NULL

You can also query the dba_profiles view exactly as in Oracle:

(enterprisedb@[local]:5445) [postgres] > x
Expanded display is off.
(enterprisedb@[local]:5445) [postgres] > select * from dba_profiles;
 profile |      resource_name       | resource_type |   limit   | common 
---------+--------------------------+---------------+-----------+--------
 DEFAULT | FAILED_LOGIN_ATTEMPTS    | PASSWORD      | UNLIMITED | NO
 DEFAULT | PASSWORD_GRACE_TIME      | PASSWORD      | UNLIMITED | NO
 DEFAULT | PASSWORD_LIFE_TIME       | PASSWORD      | UNLIMITED | NO
 DEFAULT | PASSWORD_LOCK_TIME       | PASSWORD      | UNLIMITED | NO
 DEFAULT | PASSWORD_REUSE_MAX       | PASSWORD      | UNLIMITED | NO
 DEFAULT | PASSWORD_REUSE_TIME      | PASSWORD      | UNLIMITED | NO
 DEFAULT | PASSWORD_VERIFY_FUNCTION | PASSWORD      | NULL      | NO
(7 rows)

In fact the dba_profiles view is just a view on top of edb_profile. You can verify this by:

(enterprisedb@[local]:5445) [postgres] >  d+ dba_profiles                                                        
                           View "sys.dba_profiles"
    Column     |          Type          | Modifiers | Storage  | Description 
---------------+------------------------+-----------+----------+-------------
 profile       | character varying(128) |           | extended | 
 resource_name | character varying(32)  |           | extended | 
 resource_type | character varying(8)   |           | extended | 
 limit         | character varying(128) |           | extended | 
 common        | character varying(3)   |           | extended | 
View definition:
 SELECT
        CASE
...

When there are profiles the “create user/role” syntax should have been extended, too:

(enterprisedb@[local]:5445) [postgres] > h create user
Command:     CREATE USER
Description: define a new database role
Syntax:
CREATE USER name [ [ WITH ] option [ ... ] ]

where option can be:

      SUPERUSER | NOSUPERUSER
    | CREATEDB | NOCREATEDB
    | CREATEROLE | NOCREATEROLE
    | CREATEUSER | NOCREATEUSER
    | INHERIT | NOINHERIT
    | LOGIN | NOLOGIN
    | REPLICATION | NOREPLICATION
    | CONNECTION LIMIT connlimit
    | [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'password'
    | VALID UNTIL 'timestamp'
    | PROFILE profile_name      <XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    | ACCOUNT { LOCK | UNLOCK }
    | LOCK TIME 'timestamp'
    | PASSWORD EXPIRE [ AT 'timestamp' ]
    | IN ROLE role_name [, ...]
    | IN GROUP role_name [, ...]
    | ROLE role_name [, ...]
    | ADMIN role_name [, ...]
    | USER role_name [, ...]
    | SYSID uid

I would expect that every new user gets the default profile if we do not specify one:

(enterprisedb@[local]:5445) [postgres] > create user u1 login password 'u1';
CREATE ROLE
(enterprisedb@[local]:5445) [postgres] > du+ u1
                     List of roles
 Role name |   Attributes    | Member of | Description 
-----------+-----------------+-----------+-------------
 u1        | Profile default | {}        | 

As expected. So lets play with a new profile:

(enterprisedb@[local]:5445) [postgres] > create profile my_profile;
CREATE PROFILE
Time: 18.296 ms
(enterprisedb@[local]:5445) [postgres] > alter profile my_profile limit FAILED_LOGIN_ATTEMPTS 1;
ALTER PROFILE
Time: 1.799 ms
(enterprisedb@[local]:5445) [postgres] > alter profile my_profile limit PASSWORD_LOCK_TIME 1;   
ALTER PROFILE
Time: 0.979 ms
(enterprisedb@[local]:5445) [postgres] > alter profile my_profile limit PASSWORD_LIFE_TIME 1;

Pretty much the same as in Oracle. For a full list and a description of the limits check the documentation.

Lets attach the new profile to our user:

(enterprisedb@[local]:5445) [postgres] > alter user u1 profile my_profile ;
ALTER ROLE
Time: 1.931 ms
(enterprisedb@[local]:5445) [postgres] > du u1
               List of roles
 Role name |     Attributes     | Member of 
-----------+--------------------+-----------
 u1        | Profile my_profile | {}

An important point to understand is that profiles are not per database but per instance. Once a profile is created it is available in all databases:

(enterprisedb@[local]:5445) [postgres] > c edb
You are now connected to database "edb" as user "enterprisedb".
(enterprisedb@[local]:5445) [edb] > select distinct profile from dba_profiles;
  profile   
------------
 DEFAULT
 MY_PROFILE
(2 rows)

Time: 63.333 ms
(enterprisedb@[local]:5445) [edb] > c postgres                               
You are now connected to database "postgres" as user "enterprisedb".
(enterprisedb@[local]:5445) [postgres] > select distinct profile from dba_profiles;
  profile   
------------
 DEFAULT
 MY_PROFILE
(2 rows)

Time: 2.130 ms

(enterprisedb@[local]:5445) [postgres] > create database db1;
CREATE DATABASE
Time: 1226.746 ms
(enterprisedb@[local]:5445) [postgres] > c db1
You are now connected to database "db1" as user "enterprisedb".
(enterprisedb@[local]:5445) [db1] > select distinct profile from dba_profiles;
  profile   
------------
 DEFAULT
 MY_PROFILE
(2 rows)

When profiles are global what about a password verify function you may attach to the profile? Functions are per database, aren’t they? Lets create a simple function:

create or replace function my_func ( password in varchar(30) ) return boolean
is
begin
  if ( length (password) < 5 )
  then
    raise_application_error ( -20001, 'to short');
  end if;
  return true;
end my_func;
/

And then assign this function to the profile:

(enterprisedb@[local]:5445) [postgres] > df
                             List of functions
 Schema |  Name   | Result data type |    Argument data types     |  Type  
--------+---------+------------------+----------------------------+--------
 public | my_func | boolean          | password character varying | normal
(1 row)

(enterprisedb@[local]:5445) [postgres] > alter profile my_profile limit password_verify_function my_func;
ERROR:  function my_func does not exist
Time: 0.479 ms

Hm. The function clearly exists. The issue here is that there are some specific requirements for the password verify function:

  • It needs to be owned by a super user
  • It needs to be in the sys schema
  • It needs to have the following signature: function_name (varchar2, varchar2, varchar2) return boolean

Knowing this let’s try again with this function:

CREATE OR REPLACE FUNCTION sys.my_func (username varchar2, password varchar2, old_password varchar2)  
RETURN boolean IMMUTABLE  
IS  
BEGIN  
  if ( length (password) < 5 )  
  then  
    raise_application_error ( -20001, 'too short');  
  end if;  
  return true;  
END my_func;  

To be sure lets set the owner of this function to a super user

(enterprisedb@[local]:5445) [postgres] > alter function my_func (varchar2,varchar2,varchar2) owner to enterprisedb;
ALTER FUNCTION
Time: 0.311 ms

Do we succeed now?

(enterprisedb@[local]:5445) [postgres] > alter profile my_profile limit password_verify_function my_func;
ALTER PROFILE
Time: 21.048 ms

Yes, much better. Lets do a simple test:

(enterprisedb@[local]:5445) [postgres] > alter user u1 password 'u1';
ERROR:  EDB-20001: too short
CONTEXT:  edb-spl function my_func(character varying,character varying,character varying) line 5 at procedure/function invocation statement
Time: 67.705 ms

Ok, now it really works. But what does happen if I am connected to another database where the password verify function does not exist?

(enterprisedb@[local]:5445) [postgres] > c edb
You are now connected to database "edb" as user "enterprisedb".
(enterprisedb@[local]:5445) [edb] > create user u2 password 'u2' profile my_profile;
ERROR:  password verify function is stored in database postgres
HINT:  You must connect to this database in order to assign a password.
Time: 0.644 ms
(enterprisedb@[local]:5445) [edb] > 

Ok, at least the server is telling me where I need to connect to.

This does not lock like a big new feature but it is another little piece that makes migrations from Oracle less problematic especially if there are requirements for password policies.

Let’s work together

Ready to operate at
the next level?

Tell us about your challenge. We’ll bring the depth, the expertise, and the Swiss precision.

Open source Team

Open source Team

Posts published under the Open source Team account are collective contributions by the dbi services open infrastructure consultants. The practice covers open-source databases and platforms, PostgreSQL first of all, along with MySQL, MariaDB, and Linux, from architecture, replication, and high availability to performance tuning and operations under service level agreements, and contributes actively to the PostgreSQL community.View Author posts

721 posts since September 2011

Leave a Comment

Your email address will not be published. Required fields are marked *