Skip to content

Commit

Permalink
Merge pull request #29 from RADAR-base/release-1.2.0
Browse files Browse the repository at this point in the history
Release 1.2.0
  • Loading branch information
nivemaham authored Dec 2, 2019
2 parents 2f6d0a9 + dc157b0 commit d0d8d09
Show file tree
Hide file tree
Showing 26 changed files with 735 additions and 121 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*.iml
*.ipr
/out/
local.properties

### NetBeans ###
/nbproject/private/
Expand Down
5 changes: 4 additions & 1 deletion authorizer-app/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
FROM node:8.12.0-alpine as builder

ARG BASE_HREF="/rest-sources/authorizer/"
ARG PROFILE="--prod"

WORKDIR /app

COPY package*.json /app/
RUN npm install

COPY ./ /app/

RUN $(npm bin)/ng build --prod
RUN $(npm bin)/ng build ${PROFILE} --base-href=${BASE_HREF}


FROM nginx:1.15.5-alpine
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,74 @@
<ngb-alert *ngIf="errorMessage" type="danger" (close)="errorMessage = null">{{ errorMessage}}</ngb-alert>
<ngb-alert *ngIf="errorMessage" type="danger"
(close)="errorMessage = null">{{ errorMessage}}</ngb-alert>
<div *ngIf="restSourceUser" class="container col-md-3">
<h3> Enter details for User with External User Id: {{restSourceUser.externalUserId}}</h3>
<form>
<form #userForm="ngForm">
<div class="form-group">
<label for="projectId">Project Id: </label>
<input class="form-control" name="projectId" type="text" [(ngModel)]="restSourceUser.projectId" id="projectId" placement="top" ngbTooltip="Project name from ManagementPortal">
<input class="form-control" name="projectId" type="text"
[(ngModel)]="restSourceUser.projectId" #projectId="ngModel"
id="projectId" placement="top" ngbTooltip="Project name from ManagementPortal"
required minlength="4">
</div>

<div class="form-group">
<label for="userId">User Id: </label>
<input class="form-control" name="userId" [disabled]="isEditing" type="text" [(ngModel)]="restSourceUser.userId" id="userId" placement="top" ngbTooltip="Subject Id from ManagementPortal">
<input class="form-control" name="userId" [disabled]="isEditing" type="text"
[(ngModel)]="restSourceUser.userId" #userId="ngModel"
id="userId" placement="top" ngbTooltip="Subject Id from ManagementPortal"
required minlength="4"
pattern="[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}">
</div>

<div
*ngIf="(userId.invalid && (userId.dirty || userId.touched)) || (projectId.invalid && (projectId.dirty || projectId.touched))"
class="alert alert-danger">

<div *ngIf="userId.errors?.required || projectId.errors?.required">
Project and User Id is required.
</div>
<div *ngIf="userId.errors?.minlength || projectId.errors?.minlength">
Project and User Id must be at least 4 characters long.
</div>
<div *ngIf="userId.errors?.pattern">
The pattern of the entered User Id is not correct.
</div>
</div>

<div class="form-group">
<label for="sourceId">Source Id: </label>
<input class="form-control" name="sourceId" disabled type="text" [(ngModel)]="restSourceUser.sourceId" id="sourceId">
<input class="form-control" name="sourceId" disabled type="text"
[(ngModel)]="restSourceUser.sourceId" id="sourceId">
</div>

<div class="form-group">
<label for="startDate">Start Date: </label>
<div class="input-group" placement="top" ngbTooltip="Start date to collect data from this source">
<div class="input-group" placement="top"
ngbTooltip="Start date to collect data from this source">
<input id="startDate" class="form-control" placeholder="yyyy-mm-dd"
name="startDate" [(ngModel)]="startDate" ngbDatepicker #e="ngbDatepicker">
<div class="input-group-append">
<button class="btn btn-outline-secondary calendar" (click)="e.toggle()" type="button" ></button>
<button class="btn btn-outline-secondary calendar" (click)="e.toggle()"
type="button"></button>
</div>
</div>
</div>

<div class="form-group">
<label for="endDate">End Date: </label>
<div class="input-group" placement="top" ngbTooltip="End date to collect data from this source">
<div class="input-group" placement="top"
ngbTooltip="End date to collect data from this source">
<input id="endDate" class="form-control" placeholder="yyyy-mm-dd"
name="endDate" [(ngModel)]="endDate" ngbDatepicker #d="ngbDatepicker">
<div class="input-group-append">
<button class="btn btn-outline-secondary calendar" (click)="d.toggle()" type="button"></button>
<button class="btn btn-outline-secondary calendar" (click)="d.toggle()"
type="button"></button>
</div>
</div>
</div>

<button type="button" (click)="updateRestSourceUser()" class="btn btn-success">Submit</button>
<button [disabled]="!userForm.valid" type="button" (click)="updateRestSourceUser()"
class="btn btn-success">Submit
</button>
</form>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import {RestSourceUserService} from "../../services/rest-source-user.service";
import {RestSourceUser} from "../../models/rest-source-user.model";
import {SourceClientAuthorizationService} from "../../services/source-client-authorization.service";
import {NgbDateAdapter, NgbDateNativeAdapter} from "@ng-bootstrap/ng-bootstrap";
import {HttpErrorResponse} from "@angular/common/http";

@Component({
selector: 'update-rest-source-user',
templateUrl: './update-rest-source-user.component.html',
providers: [{provide: NgbDateAdapter, useClass: NgbDateNativeAdapter}]
})
export class UpdateRestSourceUserComponent implements OnInit {
errorMessage: string;
errorMessage?: string;
restSourceUser: RestSourceUser;
startDate: Date;
endDate: Date;
Expand All @@ -35,8 +36,7 @@ export class UpdateRestSourceUserComponent implements OnInit {
this.errorMessage = 'Cannot retrieve current user details';
window.setTimeout(() => this.router.navigate(['']), 5000);
});
}
else {
} else {
this.activatedRoute.queryParams.subscribe((params: Params) => {
if (params.hasOwnProperty('error')) {
this.errorMessage = params['error_description'];
Expand All @@ -56,9 +56,19 @@ export class UpdateRestSourceUserComponent implements OnInit {
this.restSourceUserService.updateUser(this.restSourceUser).subscribe(() => {
return this.router.navigate(['/users']);
},
err => {
this.errorMessage = err.json._body;

(err: HttpErrorResponse) => {
if (err.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
this.errorMessage = "Something went wrong. Please check your connection."
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
this.errorMessage = `Backend Error: Status=${err.status},
Body: ${err.error.error}, ${err.error.message}`;
if(err.status == 417) {
this.errorMessage += " Please check the details are correct and try again.";
}
}
});
}

Expand Down
18 changes: 10 additions & 8 deletions authorizer-app/src/app/services/rest-source-user.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from '@angular/core';
import {Injectable} from '@angular/core';
import {HttpClient, HttpParams} from "@angular/common/http";
import {Observable} from "rxjs/internal/Observable";
import {RestSourceUser} from "../models/rest-source-user.model";
Expand All @@ -10,27 +10,29 @@ import {environment} from "../../environments/environment";
export class RestSourceUserService {

private serviceUrl = environment.BACKEND_BASE_URL + "/users";
constructor(private http: HttpClient) { }

constructor(private http: HttpClient) {
}

getAllUsers(): Observable<RestSourceUser[]> {
return this.http.get<RestSourceUser[]>(this.serviceUrl);
}

updateUser(sourceUser: RestSourceUser): Observable<any> {

return this.http.post(this.serviceUrl + '/' + sourceUser.id, sourceUser);
const params = new HttpParams().set("validate", String(environment.VALIDATE));
return this.http.post(this.serviceUrl + '/' + sourceUser.id, sourceUser, {params});
}

addAuthorizedUser(code: string, state: string): Observable<any> {
const params = new HttpParams()
.set('code', code)
.set('state', state);
.set('code', code)
.set('state', state);

return this.http.post(this.serviceUrl ,params);
return this.http.post(this.serviceUrl, params);
}

getUserById(userId: string): Observable<RestSourceUser> {
return this.http.get(this.serviceUrl + '/' +userId);
return this.http.get(this.serviceUrl + '/' + userId);
}

deleteUser(userId: string): Observable<any> {
Expand Down
3 changes: 2 additions & 1 deletion authorizer-app/src/environments/environment.prod.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const environment = {
production: true,
BACKEND_BASE_URL: '/rest-sources/backend'
BACKEND_BASE_URL: '/rest-sources/backend',
VALIDATE: true
};
3 changes: 2 additions & 1 deletion authorizer-app/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

export const environment = {
production: false,
BACKEND_BASE_URL: 'http://localhost:8080'
BACKEND_BASE_URL: 'http://localhost:8080',
VALIDATE: false
};

/*
Expand Down
6 changes: 5 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

group = 'org.radarcns'
version = '1.0.1'

version = '1.2.0'

sourceCompatibility = 1.8

repositories {
Expand All @@ -35,6 +37,7 @@ ext {
description = 'RADAR Rest Source Authorizer handles authorization for data access from third party APIs for wearable devices or other connected sources.'

okhttp3Version = '3.13.1'
managementPortalVersion = '0.5.8'
}

dependencies {
Expand All @@ -50,6 +53,7 @@ dependencies {
implementation('org.liquibase:liquibase-core')
implementation('org.springframework.session:spring-session-core')
implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: okhttp3Version
implementation group: 'org.radarcns', name: 'oauth-client-util', version: managementPortalVersion
runtimeOnly('org.postgresql:postgresql')
testImplementation('org.springframework.boot:spring-boot-starter-test')
}
Expand Down
5 changes: 3 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Fri Oct 04 00:13:17 BST 2019
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
Binary file added src/main/docker/etc/managementportal/keystore.p12
Binary file not shown.
8 changes: 8 additions & 0 deletions src/main/docker/etc/managementportal/oauth_client_details.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
client_id;resource_ids;client_secret;scope;authorized_grant_types;redirect_uri;authorities;access_token_validity;refresh_token_validity;additional_information;autoapprove
pRMT;res_ManagementPortal,res_gateway,res_AppServer;;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true};
aRMT;res_ManagementPortal,res_gateway;;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true};
THINC-IT;res_ManagementPortal,res_gateway;secret;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true};
radar_restapi;res_ManagementPortal;secret;SUBJECT.READ,PROJECT.READ,SOURCE.READ,SOURCETYPE.READ;password,client_credentials;;;43200;259200;{};
radar_redcap_integrator;res_ManagementPortal;secret;PROJECT.READ,SUBJECT.CREATE,SUBJECT.READ,SUBJECT.UPDATE;client_credentials;;;43200;259200;{};
radar_dashboard;res_ManagementPortal,res_RestApi;secret;SUBJECT.READ,PROJECT.READ,SOURCE.READ,SOURCETYPE.READ,MEASUREMENT.READ;client_credentials;;;43200;259200;{};
radar_rest_sources_auth;res_ManagementPortal;secret;SUBJECT.READ,PROJECT.READ;client_credentials;;;43200;259200;{};
21 changes: 21 additions & 0 deletions src/main/docker/management-portal.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
version: '2.1'

services:
#---------------------------------------------------------------------------#
# Management Portal #
#---------------------------------------------------------------------------#
managementportal:
image: radarbase/management-portal:0.5.8
ports:
- "8081:8081"
environment:
SPRING_PROFILES_ACTIVE: dev
SERVER_PORT: 8081
MANAGEMENTPORTAL_FRONTEND_CLIENT_SECRET: ""
MANAGEMENTPORTAL_COMMON_BASE_URL: http://localhost:8081
MANAGEMENTPORTAL_COMMON_MANAGEMENT_PORTAL_BASE_URL: http://localhost:8081
MANAGEMENTPORTAL_OAUTH_CLIENTS_FILE: /mp-includes/config/oauth_client_details.csv
MANAGEMENTPORTAL_CATALOGUE_SERVER_ENABLE_AUTO_IMPORT: 'false'
JAVA_OPTS: -Xmx256m # maximum heap size for the JVM running ManagementPortal, increase this as necessary
volumes:
- ./etc/managementportal/:/mp-includes/config/
44 changes: 44 additions & 0 deletions src/main/java/org/radarbase/authorizer/config/ConfigHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.radarbase.authorizer.config;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
import java.io.File;
import java.io.IOException;
import javax.naming.ConfigurationException;
import javax.validation.constraints.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ConfigHelper {

private static final Logger LOGGER = LoggerFactory.getLogger(ConfigHelper.class);

public static <T> T loadPropertiesFromFile(@NotNull String path,
@NotNull TypeReference<T> typeReference)
throws ConfigurationException {
LOGGER.info("Loading config from {}", path);
YAMLFactory yamlFactory = new YAMLFactory();
try {
YAMLParser yamlParser = yamlFactory.createParser(new File(path));
T properties = new ObjectMapper(yamlFactory)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE)
.readValue(yamlParser, typeReference);

if (properties == null) {
LOGGER.error("No valid configurations available on configured path. Please "
+ "check the syntax and file name");
throw new ConfigurationException(
"No valid configs are provided" + ".");
}
return properties;
} catch (IOException e) {
LOGGER.error("Could not successfully read config file at {}", path);
throw new ConfigurationException("Could not successfully read config file at " + path);
}
}
}
Loading

0 comments on commit d0d8d09

Please sign in to comment.