LP1904036 Verify patron credentials
authorBill Erickson <berickxx@gmail.com>
Mon, 15 Mar 2021 20:48:35 +0000 (16:48 -0400)
committerGalen Charlton <gmc@equinoxOLI.org>
Fri, 28 Oct 2022 00:13:26 +0000 (20:13 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <js7389@princeton.edu>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/circ/patron/patron.component.html
Open-ILS/src/eg2/src/app/staff/circ/patron/patron.module.ts
Open-ILS/src/eg2/src/app/staff/circ/patron/routing.module.ts
Open-ILS/src/eg2/src/app/staff/circ/patron/test-password.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/circ/patron/test-password.component.ts [new file with mode: 0644]
Open-ILS/src/perlmods/lib/OpenILS/Application/Actor.pm

index e3d477f..7f0ab27 100644 (file)
               <div *ngSwitchCase="'alerts'">
                 <eg-patron-alerts></eg-patron-alerts>
               </div>
+              <div *ngSwitchCase="'credentials'">
+                <eg-patron-test-password [patronId]="patronId">
+                </eg-patron-test-password>
+              </div>
             </ng-container>
           </ng-template>
         </li>
index 89a8473..18c6613 100644 (file)
@@ -22,6 +22,7 @@ import {BarcodesModule} from '@eg/staff/share/barcodes/barcodes.module';
 import {ItemsComponent} from './items.component';
 import {BillsComponent} from './bills.component';
 import {BillStatementComponent} from './bill-statement.component';
+import {TestPatronPasswordComponent} from './test-password.component';
 
 @NgModule({
   declarations: [
@@ -35,7 +36,8 @@ import {BillStatementComponent} from './bill-statement.component';
     BcSearchComponent,
     ItemsComponent,
     BillsComponent,
-    BillStatementComponent
+    BillStatementComponent,
+    TestPatronPasswordComponent
   ],
   imports: [
     StaffCommonModule,
index 5b53fb8..3c2da46 100644 (file)
@@ -3,6 +3,7 @@ import {RouterModule, Routes} from '@angular/router';
 import {PatronComponent} from './patron.component';
 import {BcSearchComponent} from './bcsearch.component';
 import {PatronResolver} from './resolver.service';
+import {TestPatronPasswordComponent} from './test-password.component';
 
 const routes: Routes = [{
     path: '',
@@ -13,6 +14,9 @@ const routes: Routes = [{
     loadChildren: () =>
       import('./event-log/event-log.module').then(m => m.EventLogModule)
   }, {
+    path: 'credentials',
+    component: TestPatronPasswordComponent
+  }, {
     path: 'search',
     component: PatronComponent,
     resolve: {resolver : PatronResolver}
diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/test-password.component.html b/Open-ILS/src/eg2/src/app/staff/circ/patron/test-password.component.html
new file mode 100644 (file)
index 0000000..fd458d4
--- /dev/null
@@ -0,0 +1,47 @@
+<ng-container *ngIf="!patronId">
+  <eg-staff-banner i18n-bannerText bannerText="Verify Patron Credentials">
+  </eg-staff-banner>
+</ng-container>
+<ng-container *ngIf="patronId">
+  <h3 i18n>Verify Credentials</h3>
+</ng-container>
+
+<div class="row">
+  <div class="col-lg-6">
+
+    <div class="form-group">
+      <label for="username-input" i18n>Username</label>
+      <input type="text" class="form-control" id="username-input" 
+        [disabled]="patronId" [(ngModel)]="username"/>
+    </div>
+
+    <div class="form-group">
+      <label for="barcode-input" i18n>Barcode</label>
+      <input type="text" class="form-control" id="barcode-input" 
+        [disabled]="patronId" [(ngModel)]="barcode"/>
+    </div>
+
+    <div class="form-group">
+      <label for="password-input" i18n>Password</label>
+      <input type="password" class="form-control" id="password-input" 
+        autocomplete="new-password" (keyup.enter)="verify()" [(ngModel)]="password"/>
+    </div>
+
+    <button class="btn btn-outline-dark" (click)="verify()">Verify</button>
+
+    <button class="btn btn-outline-dark ml-2" 
+      *ngIf="!patronId" (click)="retrieve()">Retrieve</button>
+
+    <hr class="m-2"/>
+
+    <div class="alert alert-success" *ngIf="verified === true" i18n>
+      Success testing credentials
+    </div>
+    <div class="alert alert-danger" *ngIf="verified === false" i18n>
+      Failure testing credentials
+    </div>
+    <div class="alert alert-danger" *ngIf="notFound" i18n>
+      No user found with the requested username / barcode
+    </div>
+  </div>
+</div>
diff --git a/Open-ILS/src/eg2/src/app/staff/circ/patron/test-password.component.ts b/Open-ILS/src/eg2/src/app/staff/circ/patron/test-password.component.ts
new file mode 100644 (file)
index 0000000..f0ae531
--- /dev/null
@@ -0,0 +1,95 @@
+import {Component, Input, OnInit, AfterViewInit, ViewChild} from '@angular/core';
+import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {from, empty, range} from 'rxjs';
+import {concatMap, tap, takeLast} from 'rxjs/operators';
+import {NgbNav, NgbNavChangeEvent} from '@ng-bootstrap/ng-bootstrap';
+import {IdlObject} from '@eg/core/idl.service';
+import {EventService} from '@eg/core/event.service';
+import {OrgService} from '@eg/core/org.service';
+import {NetService} from '@eg/core/net.service';
+import {PcrudService, PcrudContext} from '@eg/core/pcrud.service';
+import {AuthService} from '@eg/core/auth.service';
+import {PatronService} from '@eg/staff/share/patron/patron.service';
+import {PatronContextService} from './patron.service';
+
+@Component({
+  templateUrl: 'test-password.component.html',
+  selector: 'eg-patron-test-password'
+})
+export class TestPatronPasswordComponent implements OnInit, AfterViewInit {
+
+    @Input() patronId: number;
+    patron: IdlObject;
+    username = '';
+    barcode = '';
+    password = '';
+    verified = null;
+    notFound = false;
+
+    constructor(
+        private router: Router,
+        private evt: EventService,
+        private net: NetService,
+        private auth: AuthService,
+        public patronService: PatronService
+    ) {}
+
+    ngOnInit() {
+
+        if (this.patronId) {
+            this.patronService.getById(this.patronId,
+                {flesh: 1, flesh_fields: {au: ['card']}})
+            .then(p => {
+                this.patron = p;
+                this.username = p.usrname();
+                this.barcode = p.card().barcode();
+            });
+        }
+    }
+
+    ngAfterViewInit() {
+        let domId = 'password-input';
+        if (!this.patronId) { domId = 'username-input'; }
+        const node = document.getElementById(domId) as HTMLInputElement;
+        if (node) { node.focus(); }
+    }
+
+    retrieve() {
+        this.verified = null;
+        this.notFound = false;
+
+        this.net.request(
+            'open-ils.actor',
+            'open-ils.actor.user.retrieve_id_by_barcode_or_username',
+            this.auth.token(), this.barcode, this.username
+        ).subscribe(resp => {
+            if (this.evt.parse(resp)) {
+                this.notFound = true;
+            } else {
+                this.router.navigate(['/staff/circ/patron/', resp, 'checkout']);
+            }
+        });
+    }
+
+    verify() {
+        if (!this.username && !this.barcode) { return; }
+
+        this.net.request('open-ils.actor',
+            'open-ils.actor.verify_user_password', this.auth.token(),
+            this.barcode, this.username, null, this.password)
+
+        .subscribe(resp => {
+            const evt = this.evt.parse(resp);
+
+            if (evt) {
+                console.error(evt);
+                alert(evt);
+            } else if (Number(resp) === 1) {
+                this.verified = true;
+            } else {
+                this.verified = false;
+            }
+        });
+    }
+}
+
index be10105..8962dcc 100644 (file)
@@ -3517,12 +3517,13 @@ __PACKAGE__->register_method (
     api_name    => 'open-ils.actor.verify_user_password',
     signature   => q/
         Given a barcode or username and the MD5 encoded password,
+        The password can also be passed without the MD5 hashing.
         returns 1 if the password is correct.  Returns 0 otherwise.
     /
 );
 
 sub verify_user_password {
-    my($self, $conn, $auth, $barcode, $username, $password) = @_;
+    my($self, $conn, $auth, $barcode, $username, $password, $pass_nohash) = @_;
     my $e = new_editor(authtoken => $auth);
     return $e->die_event unless $e->checkauth;
     my $user;
@@ -3542,7 +3543,12 @@ sub verify_user_password {
     return 0 if (!$user || $U->is_true($user->deleted));
     return 0 if ($user_by_username && $user_by_barcode && $user_by_username->id != $user_by_barcode->id);
     return $e->event unless $e->allowed('VIEW_USER', $user->home_ou);
-    return $U->verify_migrated_user_password($e, $user->id, $password, 1);
+
+    if ($pass_nohash) {
+        return $U->verify_migrated_user_password($e, $user->id, $pass_nohash);
+    } else {
+        return $U->verify_migrated_user_password($e, $user->id, $password, 1);
+    }
 }
 
 __PACKAGE__->register_method (