Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
b2cb7c9
skip login form when authentication is done on proxy
mteodor Oct 27, 2021
aa1a934
add auth guard, add env var
mteodor Oct 27, 2021
747f3b1
add logout url
mteodor Oct 29, 2021
d3faf91
add readme section for backend behind proxy mode
mteodor Oct 29, 2021
875fb2c
remove debugging setting
mteodor Oct 29, 2021
98bfbde
revert to master
mteodor Oct 29, 2021
e9fc2a0
small corrections
mteodor Oct 29, 2021
4f30fc6
small corrections
mteodor Oct 29, 2021
91d9721
move entrypoint.sh into docker image
mteodor Nov 4, 2021
0a52307
add env var
mteodor Nov 4, 2021
4336bce
minor changes
mteodor Nov 4, 2021
9aec664
add dynamic prefix conf
mteodor Nov 5, 2021
187b0d8
remove not needed
mteodor Nov 5, 2021
7fddedd
fix linting, added proxy
mteodor Nov 10, 2021
d885d0d
minor changes, space and comments
mteodor Nov 16, 2021
28818b1
optimize url init
mteodor Nov 17, 2021
67a6d79
fix imports
mteodor Nov 17, 2021
0b5c41b
skip login form when authentication is done on proxy
mteodor Oct 27, 2021
26ec244
add auth guard, add env var
mteodor Oct 27, 2021
9bcb513
add logout url
mteodor Oct 29, 2021
f157dcd
remove debugging setting
mteodor Oct 29, 2021
cbfa560
revert to master
mteodor Oct 29, 2021
9f91313
move entrypoint.sh into docker image
mteodor Nov 4, 2021
49d5c52
add dynamic prefix conf
mteodor Nov 5, 2021
0317596
remove not needed
mteodor Nov 5, 2021
43a277c
NOISSUE - mv Twins page to Services and rm from production version
manuio Sep 20, 2021
ed47d61
NOISSUE - Use node 16.9.1 in Dockerfile
manuio Sep 22, 2021
4924684
NOISSUE - Use JSON instead of CSV for the mass provisioning
manuio Sep 22, 2021
59d8450
NOISSUE - Implement new /disconnect endpoint (list of IDs)
manuio Oct 4, 2021
1443e2f
NOISSUE - Add selec-all button on tables
manuio Oct 5, 2021
69c51a0
NOISSUE - replace Observable.throw by throwError
manuio Oct 5, 2021
34e9e8b
NOISSUE - Use node to 16.10-alpine in the Dockerfile
manuio Oct 7, 2021
adb57de
NOISSUE - Use size large for things and channels cards
manuio Oct 8, 2021
ce5a3a8
NOISSUE - Add first and last buttons for pagination
manuio Oct 8, 2021
868f095
NOISSUE - Fix pagination in details pages
manuio Oct 19, 2021
68ca787
Fix linter
manuio Oct 19, 2021
780f22d
refactoring loginUrl
mteodor Nov 23, 2021
dd5ccb8
fix login to match proxy auth
mteodor Nov 23, 2021
77dae59
fix login to match proxy auth
mteodor Nov 23, 2021
09e12c9
minor changes, environment path
mteodor Nov 23, 2021
c28a44b
remove browserlist, change constructor signature
mteodor Nov 23, 2021
4ea2dbd
remove browserlist, change constructor signature
mteodor Nov 23, 2021
9335512
fix constructor signature
mteodor Nov 23, 2021
bea6326
fix constructor signature
mteodor Nov 23, 2021
e6be2e8
fix constructor signature
mteodor Nov 23, 2021
1756a43
fix linting errors, to long line
mteodor Nov 23, 2021
4cafc04
align path routing with parent route
mteodor Nov 25, 2021
0c3760c
fix spaces
mteodor Nov 25, 2021
657de00
fix identation
mteodor Nov 25, 2021
b281d4f
replace app->ui
mteodor Nov 25, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ To remove the installed containers and volumes, run:
make clean
```

## Behind a proxy
When using authentication with proxy like Oauth2-proxy we dont need a login form. UI only needs to check if there is authenticated session by accessing `/tokens` endpoint.
Request to `/tokens` endpoint in this use case is also handled by proxy. When UI receieves token it can be assumed that authentication is successfull, requests to backend will
be authenticated by the means of authenticated session on proxy so `token` is not needed to authenticate requests but it may be used for restricting access to some endpoints (e.g. based on a role in token)
To use UI in this mode where backend is behind authentication proxy you need to set envs in `.env`.
* `MF_PROXY_AUTH=true`
* `MF_PROXY_LOGOUT_URL=/logout (this may be optional depending on the proxy being used)`


## Preview

##
Expand Down
3 changes: 3 additions & 0 deletions docker/.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
## UI
MF_UI_PORT=3000
MF_UI_MQTT_WS_URL=ws://localhost/mqtt
MF_PROXY_AUTH=false
MF_PROXY_LOGOUT_URL=/logout
MF_UI_APP_PREFIX='ui'

## NginX
MF_NGINX_HTTP_PORT=80
Expand Down
4 changes: 4 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
# Stage 0, based on Node.js, to build and compile Angular
FROM node:16.10-alpine as node
WORKDIR /app
RUN mkdir /app/dist
COPY package.json /app/
COPY package-lock.json /app/
RUN npm install
COPY ./ /app/

RUN npm run build:prod

# Stage 1, based on Nginx, to have only the compiled app, ready for production with Nginx
FROM nginx:1.13-alpine
COPY --from=node /app/dist/ /usr/share/nginx/html
COPY docker/nginx/entrypoint-ui.sh /entrypoint.sh
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf
ENTRYPOINT [ "/entrypoint.sh" ]
7 changes: 4 additions & 3 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ services:
image: mainflux/ui:latest
container_name: mainflux-ui
restart: on-failure
volumes:
- ./nginx/entrypoint-ui.sh:/entrypoint.sh
ports:
- ${MF_UI_PORT}:${MF_UI_PORT}
networks:
- mainflux-base-net
environment:
MF_UI_PORT: ${MF_UI_PORT}
MF_UI_MQTT_WS_URL: ${MF_UI_MQTT_WS_URL}
MF_PROXY_AUTH: ${MF_PROXY_AUTH}
MF_PROXY_LOGOUT_URL: ${MF_PROXY_LOGOUT_URL}
MF_UI_APP_PREFIX: ${MF_UI_APP_PREFIX}
command: /entrypoint.sh

nginx:
Expand Down Expand Up @@ -134,7 +135,7 @@ services:
image: mainflux/users:latest
container_name: mainflux-users
volumes:
- ./templates/${MF_USERS_RESET_PWD_TEMPLATE}:/${MF_EMAIL_TEMPLATE}
- ./templates/${MF_EMAIL_TEMPLATE}:/${MF_EMAIL_TEMPLATE}
depends_on:
- users-db
- auth
Expand Down
9 changes: 9 additions & 0 deletions docker/templates/users.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
To: {{.To}}
From: {{.From}}
Subject: {{.Subject}}
{{.Header}}
You have initiated password reset.
Follow the link below to reset password.
{{.Content}}
{{.Footer}}

15 changes: 12 additions & 3 deletions src/app/@core/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ export const NB_CORE_PROVIDERS = [
},
baseEndpoint: '',
login: {
endpoint: environment.loginUrl,
endpoint: environment.tokensUrl,
redirect: {
failure: '/',
},
},
register: {
endpoint: environment.usersUrl,
Expand All @@ -47,8 +50,14 @@ export const NB_CORE_PROVIDERS = [
endpoint: environment.resetPassUrl,
method: 'put',
},
logout:
{ method: null, redirect: { success: '/', failure: '/' } },
logout: {
method: 'get',
endpoint: environment.logoutUrl,
redirect: {
success: '/',
failure: '/',
},
},
}),
],
forms: {
Expand Down
9 changes: 7 additions & 2 deletions src/app/@theme/components/header/header.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Subject } from 'rxjs';
import { User } from 'app/common/interfaces/mainflux.interface';
import { UsersService } from 'app/common/services/users/users.service';
import { STRINGS } from 'assets/text/strings';
import { environment } from 'environments/environment';

@Component({
selector: 'ngx-header',
Expand Down Expand Up @@ -47,8 +48,8 @@ export class HeaderComponent implements OnInit, OnDestroy {

// Mainflux - Menu and version
userMenu = [
{ title: 'Profile', link: '/pages/profile' },
{ title: 'Log out', link: '/auth/logout' },
{ title: 'Profile', link: this.getLink('/pages/profile') },
{ title: 'Log out', link: this.getLink('/auth/logout') },
];

constructor(
Expand Down Expand Up @@ -112,4 +113,8 @@ export class HeaderComponent implements OnInit, OnDestroy {
this.menuService.navigateHome();
return false;
}
// Mfx - construct url with prefix
getLink (link: string) {
return environment.appPrefix === '' ? link : '/' + environment.appPrefix + '/' + link;
}
}
83 changes: 49 additions & 34 deletions src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,69 @@ import { ExtraOptions, RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core';
import {
NbAuthComponent,
NbLoginComponent,
NbRequestPasswordComponent,
NbResetPasswordComponent,
} from '@nebular/auth';

// Mfx- Custom Logout and Register components that
// replace NbLogoutComponent and NbRegisterComponent
import { LogoutComponent } from 'app/pages/logout/logout.component';
import { RegisterComponent } from 'app/pages/register/register.component';
import { LogoutComponent } from './pages/logout/logout.component';
import { RegisterComponent } from './pages/register/register.component';
import { LoginComponent } from './pages/login/login.component';
import { AuthGuard } from './auth/auth-guard.service';
import { AppComponent } from './app.component';
import { environment } from 'environments/environment';



export const routes: Routes = [
{
path: 'pages',
loadChildren: () => import('./pages/pages.module')
.then(m => m.PagesModule),
},
{
path: 'auth',
component: NbAuthComponent,
children: [
{
path: '',
component: NbLoginComponent,
},
{
path: 'login',
component: NbLoginComponent,
},
{
path: 'register',
component: RegisterComponent,
},
{
path: environment.appPrefix,
component: AppComponent,
children: [
{
path: 'logout',
component: LogoutComponent,
path: 'pages',
canActivate: [AuthGuard],
loadChildren: () => import('./pages/pages.module')
.then(m => m.PagesModule),
},
{
path: 'request-password',
component: NbRequestPasswordComponent,
},
{
path: 'reset-password',
component: NbResetPasswordComponent,
path: 'auth',
component: NbAuthComponent,
children: [
{
path: '',
component: LoginComponent,
},
{
path: 'login',
component: LoginComponent,
},
{
path: 'register',
component: RegisterComponent,
},
{
path: 'logout',
component: LogoutComponent,
},
{
path: 'request-password',
component: NbRequestPasswordComponent,
},
{
path: 'reset-password',
component: NbResetPasswordComponent,
},
],
},
{ path: '', redirectTo: 'pages', pathMatch: 'full' },
{ path: '**', redirectTo: 'pages' },
],
},
{ path: '', redirectTo: 'pages', pathMatch: 'full' },
{ path: '**', redirectTo: 'pages' },

{ path: '', redirectTo: environment.appPrefix, pathMatch: 'full' },
{ path: '**', redirectTo: environment.appPrefix },
];

const config: ExtraOptions = {
Expand Down
8 changes: 7 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@ export const MQTT_SERVICE_OPTIONS: IMqttServiceOptions = {
import { LogoutComponent } from './pages/logout/logout.component';
import { RegisterComponent } from './pages/register/register.component';
import { ProfileComponent } from './pages/profile/profile.component';
import { LoginComponent } from './pages/login/login.component';
import { AuthGuard } from './auth/auth-guard.service';

@NgModule({
declarations: [
AppComponent,
// Mfx Componennt
LogoutComponent,
LoginComponent,
RegisterComponent,
ProfileComponent,
],
Expand Down Expand Up @@ -75,7 +78,10 @@ import { ProfileComponent } from './pages/profile/profile.component';
],
bootstrap: [AppComponent],
// Mfx dependencies
providers: [MqttService],
providers: [
AuthGuard,
MqttService,
],
})
export class AppModule {
}
31 changes: 31 additions & 0 deletions src/app/auth/auth-guard.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { NbAuthService } from '@nebular/auth';
import { tap } from 'rxjs/operators';
import { environment } from 'environments/environment';


@Injectable()
export class AuthGuard implements CanActivate {
loginUrl: String;

constructor(
private authService: NbAuthService,
private router: Router,
) {
this.loginUrl = environment.appPrefix === ''
? environment.loginUrl
: environment.appPrefix + '/' + environment.loginUrl;
}

canActivate() {
return this.authService.isAuthenticated()
.pipe(
tap(authenticated => {
if (!authenticated) {
this.router.navigate([this.loginUrl]);
}
}),
);
}
}
11 changes: 8 additions & 3 deletions src/app/auth/auth.token.interceptor.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,22 @@ import { tap } from 'rxjs/operators';
import { Router } from '@angular/router';

import { NbAuthJWTToken, NbAuthService } from '@nebular/auth';

import { environment } from 'environments/environment';

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

loginUrl: string;

constructor(
private inj: Injector,
private authService: NbAuthService,
private router: Router,
) { }
) {
this.loginUrl = environment.appPrefix === ''
? environment.loginUrl
: environment.appPrefix + '/' + environment.loginUrl;
}

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.authService = this.inj.get(NbAuthService);
Expand Down Expand Up @@ -51,7 +56,7 @@ export class TokenInterceptor implements HttpInterceptor {
!request.url.startsWith(environment.httpAdapterUrl) &&
!request.url.startsWith(environment.readerUrl)) {
localStorage.removeItem('auth_app_token');
this.router.navigateByUrl('/auth/login');
this.router.navigateByUrl(this.loginUrl);
}
},
));
Expand Down
7 changes: 6 additions & 1 deletion src/app/common/services/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,17 @@ const defLimit: number = 20;
@Injectable()
export class UsersService {
picture = 'assets/images/mainflux-logo.png';
loginUrl: string;

constructor(
private http: HttpClient,
private router: Router,
private notificationsService: NotificationsService,
) { }
) {
this.loginUrl = environment.appPrefix === ''
? environment.loginUrl
: environment.appPrefix + '/' + environment.loginUrl;
}

addUser(user: User) {
return this.http.post(environment.usersUrl, user, { observe: 'response' })
Expand Down
Loading