The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

WWW::Suffit::AuthDB::Model - WWW::Suffit::AuthDB model (store) class

SYNOPSIS

    use WWW::Suffit::AuthDB::Model;

    my $model = WWW::Suffit::AuthDB::Model->new(
        "sqlite:///tmp/test.db?RaiseError=0&PrintError=0&sqlite_unicode=1"
    );

    my $model = WWW::Suffit::AuthDB::Model->new(
        "mysql://user:pass@mysql.example.com/authdb?mysql_auto_reconnect=1&mysql_enable_utf8=1"
    );

    die($model->error) unless $model->status;

DESCRIPTION

This module provides model methods

SQLITE DDL

    CREATE TABLE IF NOT EXISTS "users" (
        "id"            INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
        "username"      CHAR(64) NOT NULL UNIQUE, -- User name
        "name"          CHAR(255) DEFAULT NULL, -- Full user name
        "email"         CHAR(255) DEFAULT NULL, -- Email address
        "password"      CHAR(255) NOT NULL, -- Password hash
        "algorithm"     CHAR(64) DEFAULT NULL, -- Password hash Algorithm (SHA256)
        "role"          CHAR(255) DEFAULT NULL, -- Role name
        "flags"         INTEGER DEFAULT 0, -- Flags
        "created"       INTEGER DEFAULT NULL, -- Created at
        "not_before"    INTEGER DEFAULT NULL, -- Not Before
        "not_after"     INTEGER DEFAULT NULL, -- Not After
        "public_key"    TEXT DEFAULT NULL, -- Public Key (RSA/X509)
        "private_key"   TEXT DEFAULT NULL, -- Private Key (RSA/X509)
        "attributes"    TEXT DEFAULT NULL, -- Attributes (JSON)
        "comment"       TEXT DEFAULT NULL -- Comment
    );
    CREATE TABLE IF NOT EXISTS "groups" (
        "id"            INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
        "groupname"     CHAR(64) NOT NULL UNIQUE, -- Group name
        "description"   TEXT DEFAULT NULL -- Description
    );
    CREATE TABLE IF NOT EXISTS "realms" (
        "id"            INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
        "realmname"     CHAR(64) NOT NULL UNIQUE, -- Realm name
        "realm"         CHAR(255) DEFAULT NULL, -- Realm string
        "satisfy"       CHAR(16) DEFAULT NULL, -- The satisfy policy (All, Any)
        "description"   TEXT DEFAULT NULL -- Description
    );
    CREATE TABLE IF NOT EXISTS "routes" (
        "id"            INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
        "realmname"     CHAR(64) DEFAULT NULL, -- Realm name
        "routename"     CHAR(64) DEFAULT NULL, -- Route name
        "method"        CHAR(16) DEFAULT NULL, -- HTTP method (ANY, GET, POST, ...)
        "url"           CHAR(255) DEFAULT NULL, -- URL
        "base"          CHAR(255) DEFAULT NULL, -- Base URL
        "path"          CHAR(255) DEFAULT NULL -- Path of URL (pattern)
    );
    CREATE TABLE IF NOT EXISTS "requirements" (
        "id"            INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
        "realmname"     CHAR(64) DEFAULT NULL, -- Realm name
        "provider"      CHAR(64) DEFAULT NULL, -- Provider name (user,group,ip and etc.)
        "entity"        CHAR(64) DEFAULT NULL, -- Entity (operand of expression)
        "op"            CHAR(2) DEFAULT NULL, -- Comparison Operator
        "value"         CHAR(255) DEFAULT NULL -- Test value
    );
    CREATE TABLE IF NOT EXISTS "grpsusrs" (
        "id"            INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
        "groupname"     CHAR(64) DEFAULT NULL, -- Group name
        "username"      CHAR(64) DEFAULT NULL -- User name
    );
    CREATE TABLE IF NOT EXISTS "meta" (
        "key"           CHAR(255) NOT NULL UNIQUE PRIMARY KEY,
        "value"         TEXT DEFAULT NULL
    );
    CREATE TABLE IF NOT EXISTS "stats" (
        "id"            INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
        "address"       CHAR(40) DEFAULT NULL, -- IPv4/IPv6 client address
        "username"      CHAR(64) DEFAULT NULL, -- User name
        "dismiss"       INTEGER DEFAULT 0, -- Dismissal count
        "updated"       INTEGER DEFAULT NULL -- Update date
    );
    CREATE TABLE IF NOT EXISTS "tokens" (
        "id"            INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
        "jti"           CHAR(32) DEFAULT NULL, -- Request ID
        "username"      CHAR(64) DEFAULT NULL, -- User name
        "type"          CHAR(20) DEFAULT NULL, -- Token type (session, refresh, api)
        "clientid"      CAHR(32) DEFAULT NULL, -- Clientid as md5 (User-Agent . Remote-Address)
        "iat"           INTEGER DEFAULT NULL, -- Issue time
        "exp"           INTEGER DEFAULT NULL, -- Expiration time
        "address"       CAHR(40) DEFAULT NULL -- IPv4/IPv6 client address
    );

MYSQL DDL

    CREATE DATABASE `authdb` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_bin */;
    CREATE TABLE IF NOT EXISTS `users` (
        `id`            INT(11) NOT NULL AUTO_INCREMENT,
        `username`      VARCHAR(64) NOT NULL, -- User name
        `name`          VARCHAR(255) DEFAULT NULL, -- Full user name
        `email`         VARCHAR(255) DEFAULT NULL, -- Email address
        `password`      VARCHAR(255) NOT NULL, -- Password hash
        `algorithm`     VARCHAR(64) DEFAULT NULL, -- Password hash Algorithm (SHA256)
        `role`          VARCHAR(255) DEFAULT NULL, -- Role name
        `flags`         INT(11) DEFAULT 0, -- Flags
        `created`       INT(11) DEFAULT NULL, -- Created at
        `not_before`    INT(11) DEFAULT NULL, -- Not Before
        `not_after`     INT(11) DEFAULT NULL, -- Not After
        `public_key`    TEXT DEFAULT NULL, -- Public Key (RSA/X509)
        `private_key`   TEXT DEFAULT NULL, -- Private Key (RSA/X509)
        `attributes`    TEXT DEFAULT NULL, -- Attributes (JSON)
        `comment`       TEXT DEFAULT NULL, -- Comment
        PRIMARY KEY (`id`),
        UNIQUE KEY `username` (`username`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    CREATE TABLE IF NOT EXISTS `groups` (
        `id`            INT(11) NOT NULL AUTO_INCREMENT,
        `groupname`     VARCHAR(64) NOT NULL, -- Group name
        `description`   TEXT DEFAULT NULL, -- Description
        PRIMARY KEY (`id`),
        UNIQUE KEY `groupname` (`groupname`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    CREATE TABLE IF NOT EXISTS `realms` (
        `id`            INT(11) NOT NULL AUTO_INCREMENT,
        `realmname`     VARCHAR(64) NOT NULL, -- Realm name
        `realm`         VARCHAR(255) DEFAULT NULL, -- Realm string
        `satisfy`       VARCHAR(16) DEFAULT NULL, -- The satisfy policy (All, Any)
        `description`   TEXT DEFAULT NULL, -- Description
        PRIMARY KEY (`id`),
        UNIQUE KEY `realmname` (`realmname`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    CREATE TABLE IF NOT EXISTS `routes` (
        `id`            INT NOT NULL AUTO_INCREMENT,
        `realmname`     VARCHAR(64) DEFAULT NULL, -- Realm name
        `routename`     VARCHAR(64) DEFAULT NULL, -- Route name
        `method`        VARCHAR(16) DEFAULT NULL, -- HTTP method (ANY, GET, POST, ...)
        `url`           VARCHAR(255) DEFAULT NULL, -- URL
        `base`          VARCHAR(255) DEFAULT NULL, -- Base URL
        `path`          VARCHAR(255) DEFAULT NULL, -- Path of URL (pattern)
        PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    CREATE TABLE IF NOT EXISTS `requirements` (
        `id`            INT(11) NOT NULL AUTO_INCREMENT,
        `realmname`     VARCHAR(64) DEFAULT NULL, -- Realm name
        `provider`      VARCHAR(64) DEFAULT NULL, -- Provider name (user,group,ip and etc.)
        `entity`        VARCHAR(64) DEFAULT NULL, -- Entity (operand of expression)
        `op`            VARCHAR(2) DEFAULT NULL, -- Comparison Operator
        `value`         VARCHAR(255) DEFAULT NULL, -- Test value
        PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    CREATE TABLE IF NOT EXISTS `grpsusrs` (
        `id`            INT(11) NOT NULL AUTO_INCREMENT,
        `groupname`     VARCHAR(64) DEFAULT NULL, -- Group name
        `username`      VARCHAR(64) DEFAULT NULL, -- User name
        PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    CREATE TABLE IF NOT EXISTS `meta` (
        `key`           VARCHAR(255) NOT NULL,
        `value`         TEXT DEFAULT NULL,
        PRIMARY KEY (`key`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    CREATE TABLE IF NOT EXISTS `stats` (
        `id`            INT(11) NOT NULL AUTO_INCREMENT,
        `address`       VARCHAR(40) DEFAULT NULL, -- IPv4/IPv6 client address
        `username`      VARCHAR(64) DEFAULT NULL, -- User name
        `dismiss`       INT(11) DEFAULT 0, -- Dismissal count
        `updated`       INT(11) DEFAULT NULL, -- Update date
        PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
    CREATE TABLE IF NOT EXISTS `tokens` (
        `id`            INT(11) NOT NULL AUTO_INCREMENT,
        `jti`           VARCHAR(32) DEFAULT NULL, -- Request ID
        `username`      VARCHAR(64) DEFAULT NULL, -- User name
        `type`          VARCHAR(20) DEFAULT NULL, -- Token type (session, refresh, api)
        `clientid`      VARCHAR(32) DEFAULT NULL, -- Clientid as md5 (User-Agent . Remote-Address)
        `iat`           INT(11) DEFAULT NULL, -- Issue time
        `exp`           INT(11) DEFAULT NULL, -- Expiration time
        `address`       VARCHAR(40) DEFAULT NULL, -- IPv4/IPv6 client address
        PRIMARY KEY (`id`)
    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

METHODS

new

    my $model = WWW::Suffit::AuthDB::Model->new(
        "sqlite:///tmp/test.db?sqlite_unicode=1"
    );

Creates DBI object

error

    my $error = $model->error;

Returns error message

    my $status = $model->error( "Error message" );

Sets error message if argument is provided. This method in "set" context returns status of the operation as status() method.

dbi

    my $dbi = $model->dbi;

Returns CTK::DBI object of current database connection

dsn

    my $dsn = $model->dsn;

Returns DSN string of current database connection

group_add

    $model->group_add(
        groupname   => "wheel",
        description => "This administrator group added by default",
    ) or die($model->error);

Add new group recored

group_del

    $model->group_del("wheel") or die($model->error);

Delete record by groupname

group_get

    my %data = $model->group_get("wheel");

Returns data from database by groupname

group_getall

    my @table = $model->group_getall();

Returns pure data from database

group_members

    my @members = $model->group_members( "wheel" );

Returns members of specified group

group_set

    $model->group_set(
        username    => "wheel",
        description => "This administrator group added by default",
    ) or die($model->error);

Update recored by groupname

grpusr_add

    $model->grpusr_add(
        groupname   => "wheel",
        username    => "root",
    ) or die($model->error);

Add the user to the group

grpusr_del

    $model->grpusr_del( id => 123 ) or die($model->error);
    $model->grpusr_del( groupname => "wheel" ) or die($model->error);
    $model->grpusr_del( username => "root" ) or die($model->error);

Delete members from groups by id, groupname or username

grpusr_get

    my %data = $model->grpusr_get( id => 123 );
    my @table = $model->grpusr_get( groupname => "wheel");
    my @table = $model->grpusr_get( username => "root" );

Returns members of groups by id, groupname or username

init

Initialize DB instance. This method for internal use only

is_mysql

    print $model->is_mysql ? "Is MySQL" : "Is NOT MySQL"

Returns true if type of current database is MySQL

is_oracle

    print $model->is_oracle ? "Is Oracle" : "Is NOT Oracle"

Returns true if type of current database is Oracle

is_pg

    print $model->is_pg ? "Is PostgreSQL" : "Is NOT PostgreSQL"

Returns true if type of current database is PostgreSQL

is_sqlite

    print $model->is_sqlite ? "Is SQLite" : "Is NOT SQLite"

Returns true if type of current database is SQLite

meta_del

    $model->meta_del("key") or die($model->error);

Delete record by key

meta_get

    my %data = $model->meta_get("key");

Returns pair - key and value

    my @table = $model->meta_get();

Returns all data from meta table

meta_set

    $model->meta_set(key => "value") or die($model->error);

Set pair - key and value

ping

    $model->ping ? 'OK' : 'Database session is expired';

Checks the connection to database

realm_add

    $model->realm_add(
        realmname   => "root",
        realm       => "Root pages",
        satisfy     => "Any",
        description => "Index page",
    ) or die($model->error);

Add new realm recored

realm_del

    $model->realm_del("root") or die($model->error);

Delete record by realmname

realm_get

    my %data = $model->realm_get("root");

Returns data from database by realmname

realm_getall

    my @table = $model->realm_getall();

Returns pure data from database

realm_requirement_add

    $model->realm_requirement_add(
        realmname   => "root",
        provider    => "user",
        entity      => "username",
        op          => "eq",
        value       => "admin",
    ) or die($model->error);

Add the new requirement

realm_requirement_del

    $model->realm_requirement_del("default") or die($model->error);

Delete requirements by realmname

realm_requirements

    my @table = $model->realm_requirements("default");

Returns realm's requirements from database by realmname

realm_routes

    my @table = $model->realm_routes( "realmname" );

Returns realm's routes from database by realmname

realm_set

    $model->realm_set(
        realmname   => "root",
        realm       => "Root pages",
        satisfy     => "Any",
        description => "Index page (modified)",
    ) or die($model->error);

Update recored by realmname

reconnect

    $model->reconnect;

This method performs reconnecting to database and returns model object

route_add

    $model->route_add(
        realmname   => "root",
        routename   => "root",
        method      => "GET",
        url         => "https://localhost:8695/foo/bar",
        base        => "https://localhost:8695/`,
        path        => "/foo/bar",
    ) or die($model->error);

Add the new route to realm

route_del

    $model->route_del(123) or die($model->error);

Delete record by id

    $model->route_del("root") or die($model->error);

Delete record by realmname

route_release

    $model->route_release("default") or die($model->error);

Releases the route (removes relation with realm) by realmname

route_assign

    $model->route_add(
        realmname   => "default",
        routename   => "index",
    ) or die($model->error);

Assignees the realm for route by routename

route_get

    my %data = $model->route_get(123);

Returns data from database by id

    my @table = $model->route_get("root");

Returns data from database by realmname

route_getall

    my @table = $model->route_getall();

Returns pure data from database

    my @routes = $model->route_search( "ind" );

Performs search route by specified fragment and returns list of found routes

route_set

    $model->route_set(
        id          => 123,
        realmname   => "root",
        routename   => "root",
        method      => "POST",
        url         => "https://localhost:8695",
        base        => "https://localhost:8695/`,
        path        => "/foo/bar",
    ) or die($model->error);

Update record by id

stat_get

    my %st = $model->stat_get($address, $username);

Returns statistic information by address and username

stat_set

    $model->stat_set(
        address => $address,
        username => $username,
        dismiss => 1,
        updated => time,
    ) or die($model->error);

Sets statistic information by address and username

status

    my $status = $model->status;
    my $status = $model->status( 1 ); # Sets the status value and returns it

Gets or sets the BOOL status of the operation

token_add

    $model->token_add(
        type        => 'api',
        jti         => $jti,
        username    => $username,
        clientid    => 'qwertyuiqwertyui',
        iat         => time,
        exp         => time + 3600,
        address     => '127.0.0.1',
    ) or die($model->error);

Adds new token for user

token_del

    $model->token_del( 123 ) or die($model->error);

Delete record by id

    $model->token_del() or die($model->error);

Delete all expired tokens

token_get

    my %data = $model->token_get( 123 );

Returns data from database by id

token_get_cond

    my %data = $model->token_get_cond('api', username => $username, jti => $jti);
    my %data = $model->token_get_cond('session', username => $username, clientid => $clientid);

Returns data from database by id jti or clientid

token_getall

    my @table = $model->token_getall();

Returns all tokens

token_set

    $model->token_set(
        id          => 123,
        type        => 'api',
        jti         => $jti,
        username    => $username,
        clientid    => 'qwertyuiqwertyui',
        iat         => time,
        exp         => time + 3600,
        address     => '127.0.0.1',
    ) or die($model->error);

Update record by id

user_add

    $model->user_add(
        username    => "admin",
        name        => "Administrator",
        email       => 'root@localhost',
        password    => "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",
        algorithm   => "SHA256",
        role        => "System administrator",
        flags       => 0,
        created     => time(),
        not_before  => time(),
        not_after   => undef,
        public_key  => "",
        private_key => "",
        attributes  => qq/{"disabled": 0}/,
        comment     => "This user added by default",
    ) or die($model->error);

Add new user recored

user_del

    $model->user_del("admin") or die($model->error);

Delete record by username

user_edit

    $model->user_edit(
        id          => 123,
        username    => $username,
        comment     => $comment,
        email       => $email,
        name        => $name,
        role        => $role,
    ) or die($model->error);

Edit user data by id

user_get

    my %data = $model->user_get("admin");

Returns data from database by username

user_getall

    my @table = $model->user_getall();

Returns pure data from database (array of hash)

user_groups

    my @groups = $model->user_groups( "admin" );

Returns groups of specified user

user_passwd

    $model->user_passwd(
        username    => "admin",
        password    => "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",
    ) or die($model->error);

Changes password for user

    my @users = $model->user_search( "ad" );

Performs search user by specified fragment and returns list of found users

user_set

    $model->user_set(
        username    => "admin",
        name        => "Administrator",
        email       => 'root@localhost',
        password    => "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918",
        algorithm   => "SHA256",
        role        => "System administrator",
        flags       => 0,
        not_before  => time(),
        not_after   => undef,
        public_key  => "",
        private_key => "",
        attributes  => qq/{"disabled": 0}/,
        comment     => "This user added by default",
    ) or die($model->error);

Update recored by username

user_setkeys

    $model->user_setkeys(
        id          => 123,
        public_key  => $public_key,
        private_key => $private_key,
    ) or die($model->error);

Sets keys to user's data

user_tokens

    my @table = $model->user_tokens($username);

Returns all tokens for user

HISTORY

See Changes file

TO DO

See TODO file

SEE ALSO

WWW::Suffit::AuthDB, CTK::DBI

AUTHOR

Serż Minus (Sergey Lepenkov) https://www.serzik.com <abalama@cpan.org>

COPYRIGHT

Copyright (C) 1998-2023 D&D Corporation. All Rights Reserved

LICENSE

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

See LICENSE file and https://dev.perl.org/licenses/