View | Details | Raw Unified | Return to bug 17004
Collapse All | Expand All

(-)a/Koha/REST/V1/Auth.pm (+101 lines)
Line 0 Link Here
1
package Koha::REST::V1::Auth;
2
3
# Copyright 2016 Koha-Suomi
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Mojo::Base 'Mojolicious::Controller';
23
24
use Koha::Patrons;
25
use C4::Auth;
26
27
use CGI;
28
29
sub login {
30
    my ($c, $args, $cb) = @_;
31
32
    my $userid = $args->{userid} || $args->{cardnumber};
33
    my $password = $args->{password};
34
    my $patron;
35
36
    return $c->$cb({ error => "Either userid or cardnumber is required "
37
                             ."- neither given." }, 403) unless ($userid);
38
39
    my $cgi = CGI->new;
40
    $cgi->param(userid => $userid);
41
    $cgi->param(password => $password);
42
    my ($status, $cookie, $sessionid) = C4::Auth::check_api_auth($cgi);
43
44
    return $c->$cb({ error => "Login failed." }, 401) if $status eq "failed";
45
    return $c->$cb({ error => "Session expired." }, 401) if $status eq "expired";
46
    return $c->$cb({ error => "Database is under maintenance." }, 401) if $status eq "maintenance";
47
    return $c->$cb({ error => "Login failed." }, 401) unless $status eq "ok";
48
49
    $patron = Koha::Patrons->find({ userid => $userid }) unless $patron;
50
    $patron = Koha::Patrons->find({ cardnumber => $userid }) unless $patron;
51
52
    my $session = _swaggerize_session($sessionid, $patron);
53
54
    $c->cookie(CGISESSID => $sessionid, { path => "/" });
55
56
    return $c->$cb($session, 201);
57
}
58
59
sub logout {
60
    my ($c, $args, $cb) = @_;
61
62
    my $sessionid = $args->{session}->{sessionid};
63
    $sessionid = $c->cookie('CGISESSID') unless $sessionid;
64
65
    my ($status, $sid) = C4::Auth::check_cookie_auth($sessionid);
66
    unless ($status eq "ok") {
67
        return $c->$cb({ error => "Invalid session id."}, 401);
68
    }
69
70
    $c->cookie(CGISESSID => $sessionid, { path => "/", expires => 1 });
71
72
    my $session = C4::Auth::get_session($sessionid);
73
    $session->delete;
74
    $session->flush;
75
    return $c->$cb({}, 200);
76
}
77
78
sub _swaggerize_session {
79
    my ($sessionid, $patron) = @_;
80
81
    return unless ref($patron) eq 'Koha::Patron';
82
83
    my $rawPermissions = C4::Auth::haspermission($patron->userid); # defaults to all permissions
84
    my @permissions;
85
86
    # delete all empty permissions
87
    while ( my ($key, $val) = each %{$rawPermissions} ) {
88
        push @permissions, $key if $val;
89
    }
90
91
    return {
92
        borrowernumber => $patron->borrowernumber,
93
        firstname => $patron->firstname,
94
        surname  => $patron->surname,
95
        email     => $patron->email,
96
        sessionid => $sessionid,
97
	permissions => \@permissions,
98
    };
99
}
100
101
1;
(-)a/api/v1/swagger/definitions.json (+3 lines)
Lines 1-4 Link Here
1
{
1
{
2
  "session": {
3
    "$ref": "definitions/session.json"
4
  },
2
  "patron": {
5
  "patron": {
3
    "$ref": "definitions/patron.json"
6
    "$ref": "definitions/patron.json"
4
  },
7
  },
(-)a/api/v1/swagger/definitions/session.json (+32 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "borrowernumber": {
5
      "type": "string",
6
      "description": "internally assigned user identifier"
7
    },
8
    "email": {
9
      "type": ["string", "null"],
10
      "description": "primary email address for patron's primary address"
11
    },
12
    "surname": {
13
      "type": "string",
14
      "description": "patron's last name"
15
    },
16
    "firstname": {
17
      "type": ["string", "null"],
18
      "description": "patron's first name"
19
    },
20
    "sessionid": {
21
      "description": "Koha Session identifier",
22
      "type": "string"
23
    },
24
    "permissions": {
25
      "description": "patron's permissions",
26
      "type": "array",
27
      "items": {
28
        "type": "string"
29
      }
30
    }
31
  }
32
}
(-)a/api/v1/swagger/definitions/sessionid.json (+10 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "sessionid": {
5
      "description": "The Koha sessionid",
6
      "type": "string"
7
    }
8
  },
9
  "required": ["sessionid"]
10
}
(-)a/api/v1/swagger/parameters.json (+12 lines)
Lines 7-11 Link Here
7
  },
7
  },
8
  "holdIdPathParam": {
8
  "holdIdPathParam": {
9
    "$ref": "parameters/hold.json#/holdIdPathParam"
9
    "$ref": "parameters/hold.json#/holdIdPathParam"
10
  },
11
  "cardnumberPostParam": {
12
    "$ref": "parameters/auth.json#/cardnumberPostParam"
13
  },
14
  "passwordPostParam": {
15
   "$ref": "parameters/auth.json#/passwordPostParam"
16
  },
17
  "useridPostParam": {
18
   "$ref": "parameters/auth.json#/useridPostParam"
19
  },
20
  "sessionidBodyParam": {
21
   "$ref": "parameters/auth.json#/sessionidBodyParam"
10
  }
22
  }
11
}
23
}
(-)a/api/v1/swagger/parameters/auth.json (+31 lines)
Line 0 Link Here
1
{
2
  "cardnumberPostParam": {
3
    "name": "cardnumber",
4
    "in": "formData",
5
    "description": "Borrower's card's barcode/identifier",
6
    "required": false,
7
    "type": "string"
8
  },
9
  "passwordPostParam": {
10
    "name": "password",
11
    "in": "formData",
12
    "required": true,
13
    "type": "string"
14
  },
15
  "useridPostParam": {
16
    "name": "userid",
17
    "in": "formData",
18
    "description": "The userid of the Borrower, unique value",
19
    "required": false,
20
    "type": "string"
21
  },
22
  "sessionidBodyParam": {
23
    "name": "session",
24
    "description": "The CGISESSID Cookie used to authenticate a session",
25
    "in": "body",
26
    "required": false,
27
    "schema" : {
28
      "$ref": "../definitions/sessionid.json"
29
    }
30
  }
31
}
(-)a/api/v1/swagger/paths.json (+3 lines)
Lines 1-4 Link Here
1
{
1
{
2
  "/auth/session": {
3
    "$ref": "paths/auth.json#/~1auth~1session"
4
  },
2
  "/holds": {
5
  "/holds": {
3
    "$ref": "paths/holds.json#/~1holds"
6
    "$ref": "paths/holds.json#/~1holds"
4
  },
7
  },
(-)a/api/v1/swagger/paths/auth.json (+58 lines)
Line 0 Link Here
1
{
2
  "/auth/session": {
3
    "post": {
4
      "operationId": "loginAuth",
5
      "tags": ["auth"],
6
      "summary": "Login to Koha and get a session cookie",
7
      "description": "Makes a 'normal' username + password login to Koha, and returns the sessionid you need put to the CGISESSID-cookie. Koha uses this cookie to track a session.\nBe aware that the authenticated session most probably is IP-locked so authenticating from one IP and passing the session to another wont work.",
8
      "parameters": [
9
        { "$ref": "../parameters.json#/cardnumberPostParam" },
10
        { "$ref": "../parameters.json#/useridPostParam" },
11
        { "$ref": "../parameters.json#/passwordPostParam" }
12
      ],
13
      "produces": [
14
        "application/json"
15
      ],
16
      "responses": {
17
        "201": {
18
          "description": "A borrower with SSO-relevant fields",
19
          "schema": {
20
            "$ref": "../definitions.json#/session"
21
          }
22
        },
23
        "401": {
24
          "description": "Bad username/cardnumber and/or password",
25
          "schema": {
26
            "$ref": "../definitions.json#/error"
27
          }
28
        }
29
      }
30
    },
31
    "delete": {
32
      "operationId": "logoutAuth",
33
      "tags": ["auth"],
34
      "summary": "Logout from Koha.",
35
      "description": "Logouts user from Koha by marking session as expired. sessionid is optional, if not given, logs out currently logged in user",
36
      "parameters": [
37
        { "$ref": "../parameters.json#/sessionidBodyParam" }
38
      ],
39
      "produces": [
40
        "application/json"
41
      ],
42
      "responses": {
43
        "200": {
44
          "description": "Successfully logged out",
45
          "schema": {
46
            "type": "object"
47
          }
48
        },
49
        "401": {
50
          "description": "Bad session id",
51
          "schema": {
52
            "$ref": "../definitions.json#/error"
53
          }
54
        }
55
      }
56
    }
57
  }
58
}
(-)a/t/db_dependent/api/v1/auth.t (-1 / +140 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env perl
2
3
# Copyright 2016 Koha-Suomi
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 3 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use Test::More tests => 38;
23
use Test::Mojo;
24
25
use t::lib::TestBuilder;
26
27
use C4::Auth;
28
use C4::Context;
29
use Koha::AuthUtils;
30
31
my $builder = t::lib::TestBuilder->new();
32
33
my $dbh = C4::Context->dbh;
34
$dbh->{AutoCommit} = 0;
35
$dbh->{RaiseError} = 1;
36
37
$ENV{REMOTE_ADDR} = '127.0.0.1';
38
my $t = Test::Mojo->new('Koha::REST::V1');
39
40
my $categorycode = $builder->build({ source => 'Category' })->{ categorycode };
41
my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode };
42
my $password = "2anxious? if someone finds out";
43
44
my $borrower = $builder->build({
45
    source => 'Borrower',
46
    value => {
47
        branchcode   => $branchcode,
48
        categorycode => $categorycode,
49
        password => Koha::AuthUtils::hash_password($password),
50
    }
51
});
52
53
my $auth_by_userid = {
54
    userid => $borrower->{userid},
55
    password => $password,
56
};
57
my $auth_by_cardnumber = {
58
    cardnumber => $borrower->{cardnumber},
59
    password => $password,
60
};
61
my $invalid_login = {
62
    userid => $borrower->{userid},
63
    password => "please let me in",
64
};
65
my $invalid_login2 = {
66
    cardnumber => $borrower->{cardnumber},
67
    password => "my password is password, don't tell anyone",
68
};
69
70
my $tx = $t->ua->build_tx(POST => '/api/v1/auth/session' => form => $auth_by_userid);
71
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
72
$t->request_ok($tx)
73
  ->status_is(201)
74
  ->json_is('/firstname', $borrower->{firstname})
75
  ->json_is('/surname', $borrower->{surname})
76
  ->json_is('/borrowernumber', $borrower->{borrowernumber})
77
  ->json_is('/email', $borrower->{email})
78
  ->json_has('/sessionid');
79
80
$tx = $t->ua->build_tx(POST => '/api/v1/auth/session' => form => $auth_by_cardnumber);
81
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
82
$t->request_ok($tx)
83
  ->status_is(201)
84
  ->json_is('/firstname', $borrower->{firstname})
85
  ->json_is('/surname', $borrower->{surname})
86
  ->json_is('/borrowernumber', $borrower->{borrowernumber})
87
  ->json_is('/email', $borrower->{email})
88
  ->json_has('/sessionid');
89
my $sessionid = $tx->res->json->{sessionid};
90
91
$tx = $t->ua->build_tx(POST => '/api/v1/auth/session' => form => $invalid_login);
92
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
93
$t->request_ok($tx)
94
  ->status_is(401)
95
  ->json_is('/error', "Login failed.");
96
97
$tx = $t->ua->build_tx(POST => '/api/v1/auth/session' => form => $invalid_login2);
98
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
99
$t->request_ok($tx)
100
  ->status_is(401)
101
  ->json_is('/error', "Login failed.");
102
103
$tx = $t->ua->build_tx(DELETE => '/api/v1/auth/session' => json => { sessionid => $sessionid."123" });
104
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
105
$t->request_ok($tx)
106
  ->status_is(401)
107
  ->json_is('/error', "Invalid session id.");
108
109
my ($sess_status, $sid) = C4::Auth::check_cookie_auth($sessionid);
110
is($sess_status, "ok", "Session is valid before logging out.");
111
$tx = $t->ua->build_tx(DELETE => '/api/v1/auth/session' => json => { sessionid => $sessionid });
112
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
113
$t->request_ok($tx)
114
  ->status_is(200);
115
116
($sess_status, $sid) = C4::Auth::check_cookie_auth($sessionid);
117
isnt($sess_status, "ok", "Session is not valid after logging out.");
118
119
$tx = $t->ua->build_tx(POST => '/api/v1/auth/session' => form => $auth_by_cardnumber);
120
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
121
$t->request_ok($tx)
122
  ->status_is(201)
123
  ->json_is('/firstname', $borrower->{firstname})
124
  ->json_is('/surname', $borrower->{surname})
125
  ->json_is('/borrowernumber', $borrower->{borrowernumber})
126
  ->json_is('/email', $borrower->{email})
127
  ->json_has('/sessionid');
128
$sessionid = $tx->res->json->{sessionid};
129
130
($sess_status, $sid) = C4::Auth::check_cookie_auth($sessionid);
131
is($sess_status, "ok", "Session is valid before logging out.");
132
$tx = $t->ua->build_tx(DELETE => '/api/v1/auth/session');
133
$tx->req->env({REMOTE_ADDR => '127.0.0.1'});
134
$t->request_ok($tx)
135
  ->status_is(200);
136
137
($sess_status, $sid) = C4::Auth::check_cookie_auth($sessionid);
138
isnt($sess_status, "ok", "Session is not valid after logging out.");
139
140
$dbh->rollback;

Return to bug 17004