mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[CST-5309] Added LoginOrcid component
This commit is contained in:

committed by
Luca Giamminonni

parent
45887154b6
commit
e68e605211
@@ -4,5 +4,6 @@ export enum AuthMethodType {
|
|||||||
Ldap = 'ldap',
|
Ldap = 'ldap',
|
||||||
Ip = 'ip',
|
Ip = 'ip',
|
||||||
X509 = 'x509',
|
X509 = 'x509',
|
||||||
Oidc = 'oidc'
|
Oidc = 'oidc',
|
||||||
|
Orcid = 'orcid'
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,11 @@ export class AuthMethod {
|
|||||||
this.location = location;
|
this.location = location;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'orcid': {
|
||||||
|
this.authMethodType = AuthMethodType.Orcid;
|
||||||
|
this.location = location;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
<button class="btn btn-lg btn-primary btn-block mt-2 text-white" (click)="redirectToOrcid()">
|
||||||
|
<i class="fas fa-sign-in-alt"></i> {{"login.form.orcid" | translate}}
|
||||||
|
</button>
|
@@ -0,0 +1,155 @@
|
|||||||
|
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { provideMockStore } from '@ngrx/store/testing';
|
||||||
|
import { Store, StoreModule } from '@ngrx/store';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { EPerson } from '../../../../core/eperson/models/eperson.model';
|
||||||
|
import { EPersonMock } from '../../../testing/eperson.mock';
|
||||||
|
import { authReducer } from '../../../../core/auth/auth.reducer';
|
||||||
|
import { AuthService } from '../../../../core/auth/auth.service';
|
||||||
|
import { AuthServiceStub } from '../../../testing/auth-service.stub';
|
||||||
|
import { storeModuleConfig } from '../../../../app.reducer';
|
||||||
|
import { AuthMethod } from '../../../../core/auth/models/auth.method';
|
||||||
|
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
||||||
|
import { LogInOrcidComponent } from './log-in-orcid.component';
|
||||||
|
import { NativeWindowService } from '../../../../core/services/window.service';
|
||||||
|
import { RouterStub } from '../../../testing/router.stub';
|
||||||
|
import { ActivatedRouteStub } from '../../../testing/active-router.stub';
|
||||||
|
import { NativeWindowMockFactory } from '../../../mocks/mock-native-window-ref';
|
||||||
|
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
|
||||||
|
|
||||||
|
|
||||||
|
describe('LogInOrcidComponent', () => {
|
||||||
|
|
||||||
|
let component: LogInOrcidComponent;
|
||||||
|
let fixture: ComponentFixture<LogInOrcidComponent>;
|
||||||
|
let page: Page;
|
||||||
|
let user: EPerson;
|
||||||
|
let componentAsAny: any;
|
||||||
|
let setHrefSpy;
|
||||||
|
let orcidBaseUrl;
|
||||||
|
let location;
|
||||||
|
let initialState: any;
|
||||||
|
let hardRedirectService: HardRedirectService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
user = EPersonMock;
|
||||||
|
orcidBaseUrl = 'dspace-rest.test/orcid?redirectUrl=';
|
||||||
|
location = orcidBaseUrl + 'http://dspace-angular.test/home';
|
||||||
|
|
||||||
|
hardRedirectService = jasmine.createSpyObj('hardRedirectService', {
|
||||||
|
getCurrentRoute: {},
|
||||||
|
redirect: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
initialState = {
|
||||||
|
core: {
|
||||||
|
auth: {
|
||||||
|
authenticated: false,
|
||||||
|
loaded: false,
|
||||||
|
blocking: false,
|
||||||
|
loading: false,
|
||||||
|
authMethods: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(waitForAsync(() => {
|
||||||
|
// refine the test module by declaring the test component
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
StoreModule.forRoot({ auth: authReducer }, storeModuleConfig),
|
||||||
|
TranslateModule.forRoot()
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
LogInOrcidComponent
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: AuthService, useClass: AuthServiceStub },
|
||||||
|
{ provide: 'authMethodProvider', useValue: new AuthMethod(AuthMethodType.Orcid, location) },
|
||||||
|
{ provide: 'isStandalonePage', useValue: true },
|
||||||
|
{ provide: NativeWindowService, useFactory: NativeWindowMockFactory },
|
||||||
|
{ provide: Router, useValue: new RouterStub() },
|
||||||
|
{ provide: ActivatedRoute, useValue: new ActivatedRouteStub() },
|
||||||
|
{ provide: HardRedirectService, useValue: hardRedirectService },
|
||||||
|
provideMockStore({ initialState }),
|
||||||
|
],
|
||||||
|
schemas: [
|
||||||
|
CUSTOM_ELEMENTS_SCHEMA
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
// create component and test fixture
|
||||||
|
fixture = TestBed.createComponent(LogInOrcidComponent);
|
||||||
|
|
||||||
|
// get test component from the fixture
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
componentAsAny = component;
|
||||||
|
|
||||||
|
// create page
|
||||||
|
page = new Page(component, fixture);
|
||||||
|
setHrefSpy = spyOnProperty(componentAsAny._window.nativeWindow.location, 'href', 'set').and.callThrough();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the properly a new redirectUrl', () => {
|
||||||
|
const currentUrl = 'http://dspace-angular.test/collections/12345';
|
||||||
|
componentAsAny._window.nativeWindow.location.href = currentUrl;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
||||||
|
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
||||||
|
|
||||||
|
component.redirectToOrcid();
|
||||||
|
|
||||||
|
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set a new redirectUrl', () => {
|
||||||
|
const currentUrl = 'http://dspace-angular.test/home';
|
||||||
|
componentAsAny._window.nativeWindow.location.href = currentUrl;
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
expect(componentAsAny.injectedAuthMethodModel.location).toBe(location);
|
||||||
|
expect(componentAsAny._window.nativeWindow.location.href).toBe(currentUrl);
|
||||||
|
|
||||||
|
component.redirectToOrcid();
|
||||||
|
|
||||||
|
expect(setHrefSpy).toHaveBeenCalledWith(currentUrl);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I represent the DOM elements and attach spies.
|
||||||
|
*
|
||||||
|
* @class Page
|
||||||
|
*/
|
||||||
|
class Page {
|
||||||
|
|
||||||
|
public emailInput: HTMLInputElement;
|
||||||
|
public navigateSpy: jasmine.Spy;
|
||||||
|
public passwordInput: HTMLInputElement;
|
||||||
|
|
||||||
|
constructor(private component: LogInOrcidComponent, private fixture: ComponentFixture<LogInOrcidComponent>) {
|
||||||
|
// use injector to get services
|
||||||
|
const injector = fixture.debugElement.injector;
|
||||||
|
const store = injector.get(Store);
|
||||||
|
|
||||||
|
// add spies
|
||||||
|
this.navigateSpy = spyOn(store, 'dispatch');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
110
src/app/shared/log-in/methods/orcid/log-in-orcid.component.ts
Normal file
110
src/app/shared/log-in/methods/orcid/log-in-orcid.component.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import { Component, Inject, OnInit, } from '@angular/core';
|
||||||
|
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { select, Store } from '@ngrx/store';
|
||||||
|
|
||||||
|
import { renderAuthMethodFor } from '../log-in.methods-decorator';
|
||||||
|
import { AuthMethodType } from '../../../../core/auth/models/auth.method-type';
|
||||||
|
import { AuthMethod } from '../../../../core/auth/models/auth.method';
|
||||||
|
|
||||||
|
import { CoreState } from '../../../../core/core.reducers';
|
||||||
|
import { isAuthenticated, isAuthenticationLoading } from '../../../../core/auth/selectors';
|
||||||
|
import { NativeWindowRef, NativeWindowService } from '../../../../core/services/window.service';
|
||||||
|
import { isNotNull, isEmpty } from '../../../empty.util';
|
||||||
|
import { AuthService } from '../../../../core/auth/auth.service';
|
||||||
|
import { HardRedirectService } from '../../../../core/services/hard-redirect.service';
|
||||||
|
import { take } from 'rxjs/operators';
|
||||||
|
import { URLCombiner } from '../../../../core/url-combiner/url-combiner';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-log-in-orcid',
|
||||||
|
templateUrl: './log-in-orcid.component.html',
|
||||||
|
})
|
||||||
|
@renderAuthMethodFor(AuthMethodType.Orcid)
|
||||||
|
export class LogInOrcidComponent implements OnInit {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authentication method data.
|
||||||
|
* @type {AuthMethod}
|
||||||
|
*/
|
||||||
|
public authMethod: AuthMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if the authentication is loading.
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
public loading: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The orcid authentication location url.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public location: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether user is authenticated.
|
||||||
|
* @type {Observable<string>}
|
||||||
|
*/
|
||||||
|
public isAuthenticated: Observable<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {AuthMethod} injectedAuthMethodModel
|
||||||
|
* @param {boolean} isStandalonePage
|
||||||
|
* @param {NativeWindowRef} _window
|
||||||
|
* @param {AuthService} authService
|
||||||
|
* @param {HardRedirectService} hardRedirectService
|
||||||
|
* @param {Store<State>} store
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
@Inject('authMethodProvider') public injectedAuthMethodModel: AuthMethod,
|
||||||
|
@Inject('isStandalonePage') public isStandalonePage: boolean,
|
||||||
|
@Inject(NativeWindowService) protected _window: NativeWindowRef,
|
||||||
|
private authService: AuthService,
|
||||||
|
private hardRedirectService: HardRedirectService,
|
||||||
|
private store: Store<CoreState>
|
||||||
|
) {
|
||||||
|
this.authMethod = injectedAuthMethodModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
// set isAuthenticated
|
||||||
|
this.isAuthenticated = this.store.pipe(select(isAuthenticated));
|
||||||
|
|
||||||
|
// set loading
|
||||||
|
this.loading = this.store.pipe(select(isAuthenticationLoading));
|
||||||
|
|
||||||
|
// set location
|
||||||
|
this.location = decodeURIComponent(this.injectedAuthMethodModel.location);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectToOrcid() {
|
||||||
|
|
||||||
|
this.authService.getRedirectUrl().pipe(take(1)).subscribe((redirectRoute) => {
|
||||||
|
if (!this.isStandalonePage) {
|
||||||
|
redirectRoute = this.hardRedirectService.getCurrentRoute();
|
||||||
|
} else if (isEmpty(redirectRoute)) {
|
||||||
|
redirectRoute = '/';
|
||||||
|
}
|
||||||
|
const correctRedirectUrl = new URLCombiner(this._window.nativeWindow.origin, redirectRoute).toString();
|
||||||
|
|
||||||
|
let orcidServerUrl = this.location;
|
||||||
|
const myRegexp = /\?redirectUrl=(.*)/g;
|
||||||
|
const match = myRegexp.exec(this.location);
|
||||||
|
const redirectUrlFromServer = (match && match[1]) ? match[1] : null;
|
||||||
|
|
||||||
|
// Check whether the current page is different from the redirect url received from rest
|
||||||
|
if (isNotNull(redirectUrlFromServer) && redirectUrlFromServer !== correctRedirectUrl) {
|
||||||
|
// change the redirect url with the current page url
|
||||||
|
const newRedirectUrl = `?redirectUrl=${correctRedirectUrl}`;
|
||||||
|
orcidServerUrl = this.location.replace(/\?redirectUrl=(.*)/g, newRedirectUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// redirect to orcid authentication url
|
||||||
|
this.hardRedirectService.redirect(orcidServerUrl);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -173,6 +173,7 @@ import { BitstreamRequestACopyPageComponent } from './bitstream-request-a-copy-p
|
|||||||
import { DsSelectComponent } from './ds-select/ds-select.component';
|
import { DsSelectComponent } from './ds-select/ds-select.component';
|
||||||
import { LogInOidcComponent } from './log-in/methods/oidc/log-in-oidc.component';
|
import { LogInOidcComponent } from './log-in/methods/oidc/log-in-oidc.component';
|
||||||
import { ThemedItemListPreviewComponent } from './object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component';
|
import { ThemedItemListPreviewComponent } from './object-list/my-dspace-result-list-element/item-list-preview/themed-item-list-preview.component';
|
||||||
|
import { LogInOrcidComponent } from './log-in/methods/orcid/log-in-orcid.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -306,6 +307,7 @@ const COMPONENTS = [
|
|||||||
|
|
||||||
LogInShibbolethComponent,
|
LogInShibbolethComponent,
|
||||||
LogInOidcComponent,
|
LogInOidcComponent,
|
||||||
|
LogInOrcidComponent,
|
||||||
LogInPasswordComponent,
|
LogInPasswordComponent,
|
||||||
LogInContainerComponent,
|
LogInContainerComponent,
|
||||||
ItemVersionsComponent,
|
ItemVersionsComponent,
|
||||||
@@ -378,6 +380,7 @@ const ENTRY_COMPONENTS = [
|
|||||||
LogInPasswordComponent,
|
LogInPasswordComponent,
|
||||||
LogInShibbolethComponent,
|
LogInShibbolethComponent,
|
||||||
LogInOidcComponent,
|
LogInOidcComponent,
|
||||||
|
LogInOrcidComponent,
|
||||||
BundleListElementComponent,
|
BundleListElementComponent,
|
||||||
ClaimedTaskActionsApproveComponent,
|
ClaimedTaskActionsApproveComponent,
|
||||||
ClaimedTaskActionsRejectComponent,
|
ClaimedTaskActionsRejectComponent,
|
||||||
|
@@ -2389,6 +2389,8 @@
|
|||||||
|
|
||||||
"login.form.oidc": "Log in with OIDC",
|
"login.form.oidc": "Log in with OIDC",
|
||||||
|
|
||||||
|
"login.form.orcid": "Log in with ORCID",
|
||||||
|
|
||||||
"login.form.password": "Password",
|
"login.form.password": "Password",
|
||||||
|
|
||||||
"login.form.shibboleth": "Log in with Shibboleth",
|
"login.form.shibboleth": "Log in with Shibboleth",
|
||||||
|
Reference in New Issue
Block a user