From ce175a8632af8884e723c6e974da645dc54185d4 Mon Sep 17 00:00:00 2001 From: Francesco Servida Date: Tue, 15 Feb 2022 22:08:48 +0100 Subject: [PATCH 1/6] Implemented basic header auth controller --- src/Ombi/Controllers/V1/TokenController.cs | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Ombi/Controllers/V1/TokenController.cs b/src/Ombi/Controllers/V1/TokenController.cs index f9ea57a5c..b8775c05b 100644 --- a/src/Ombi/Controllers/V1/TokenController.cs +++ b/src/Ombi/Controllers/V1/TokenController.cs @@ -272,5 +272,37 @@ namespace Ombi.Controllers.V1 return ip; } + + [HttpPost("header_auth")] + [ProducesResponseType(401)] + public async Task HeaderAuth() + { + string username = null; + + // Check if Header Auth is enabled and Proxy IP is trusted + // TODO + // var ombiSettings = await repo.GetSettingsAsync(); + // END TODO + + + if (Request.HttpContext?.Request?.Headers != null && Request.HttpContext.Request.Headers.ContainsKey("X-Remote-User")) + { + username = Request.HttpContext.Request.Headers["X-Remote-User"].ToString(); + + // Check if user exists + var user = await _userManager.FindByNameAsync(username); + if (user == null) + { + return new UnauthorizedResult(); + } + + return await CreateToken(true, user); + } + else + { + return new UnauthorizedResult(); + + } + } } } From d4e748fd2fc40386ad3d0475f6df6f67280c78eb Mon Sep 17 00:00:00 2001 From: Francesco Servida Date: Tue, 15 Feb 2022 23:24:13 +0100 Subject: [PATCH 2/6] Implemented Settings Interface and Models --- .../ClientApp/src/app/auth/auth.service.ts | 4 + .../ClientApp/src/app/interfaces/ISettings.ts | 2 + .../src/app/login/login.component.ts | 30 ++++- .../authentication.component.html | 121 ++++++++++-------- .../authentication.component.ts | 4 +- src/Ombi/Controllers/V1/TokenController.cs | 34 +++-- 6 files changed, 126 insertions(+), 69 deletions(-) diff --git a/src/Ombi/ClientApp/src/app/auth/auth.service.ts b/src/Ombi/ClientApp/src/app/auth/auth.service.ts index afc0a2491..ad1ff32ac 100644 --- a/src/Ombi/ClientApp/src/app/auth/auth.service.ts +++ b/src/Ombi/ClientApp/src/app/auth/auth.service.ts @@ -28,6 +28,10 @@ export class AuthService extends ServiceHelpers { return this.http.post(`${this.url}/requirePassword`, JSON.stringify(login), { headers: this.headers }); } + public headerAuth(): Observable { + return this.http.post(`${this.url}/header_auth`, {}, { headers: this.headers }); + } + public getToken() { return this.jwtHelperService.tokenGetter(); } diff --git a/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts b/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts index 8bf2755ec..1dc94f261 100644 --- a/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts +++ b/src/Ombi/ClientApp/src/app/interfaces/ISettings.ts @@ -238,6 +238,8 @@ export interface IAuthenticationSettings extends ISettings { requireNonAlphanumeric: boolean; requireUppercase: boolean; enableOAuth: boolean; + enableHeaderAuth: boolean; + headerAuthVariable: string; } export interface ICustomPage extends ISettings { diff --git a/src/Ombi/ClientApp/src/app/login/login.component.ts b/src/Ombi/ClientApp/src/app/login/login.component.ts index 235e31a8e..132554f4f 100644 --- a/src/Ombi/ClientApp/src/app/login/login.component.ts +++ b/src/Ombi/ClientApp/src/app/login/login.component.ts @@ -1,4 +1,4 @@ -import { Component, OnDestroy, OnInit, Inject } from "@angular/core"; +import { Component, OnDestroy, OnInit, Inject } from "@angular/core"; import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { TranslateService } from "@ngx-translate/core"; @@ -106,7 +106,7 @@ export class LoginComponent implements OnDestroy, OnInit { this.settingsService .getAuthentication() - .subscribe((x) => (this.authenticationSettings = x)); + .subscribe((x) => { this.authenticationSettings = x; this.headerAuth(); }); this.settingsService.getClientId().subscribe((x) => (this.clientId = x)); this.images.getRandomBackground().subscribe((x) => { this.background = this.sanitizer.bypassSecurityTrustStyle( @@ -121,7 +121,6 @@ export class LoginComponent implements OnDestroy, OnInit { if (base.length > 1) { this.baseUrl = base; } - this.translate .get("Login.Errors.IncorrectCredentials") .subscribe((x) => (this.errorBody = x)); @@ -255,6 +254,31 @@ export class LoginComponent implements OnDestroy, OnInit { ); } + public headerAuth() { + + if (this.authenticationSettings.enableHeaderAuth) { + this.authService.headerAuth().subscribe( + (x) => { + this.store.save("id_token", x.access_token); + + if (this.authService.loggedIn()) { + this.ngOnDestroy(); + this.router.navigate(["/"]); + } else { + this.notify.open(this.errorBody, "OK", { + duration: 3000, + }); + } + }, + (err) => { + this.notify.open(this.errorBody, "OK", { + duration: 3000000, + }); + } + ); + } + } + public ngOnDestroy() { clearInterval(this.timer); clearInterval(this.pinTimer); diff --git a/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.html b/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.html index 7bc6a4e80..bde67e1c7 100644 --- a/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.html +++ b/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.html @@ -1,66 +1,81 @@ - +
Authentication
-
-
- - Allow users to login without a password -
-
+
+
+ + Allow users to login without a password + +
+
-
-
- Enable Plex OAuth -
-
+
+
+ Enable Plex OAuth +
+
- +
+ +
+ +
+
-
-
-
-
-
-
+
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
--> + +
+
+
+
+
+
-
\ No newline at end of file + diff --git a/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.ts b/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.ts index 6f140f8af..386711c4f 100644 --- a/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { FormBuilder, FormGroup } from "@angular/forms"; import { NotificationService } from "../../services"; @@ -26,6 +26,8 @@ export class AuthenticationComponent implements OnInit { requireNonAlphanumeric: [x.requireNonAlphanumeric], requireUppercase: [x.requireUppercase], enableOAuth: [x.enableOAuth], + enableHeaderAuth: [x.enableHeaderAuth], + headerAuthVariable: [x.headerAuthVariable], }); }); } diff --git a/src/Ombi/Controllers/V1/TokenController.cs b/src/Ombi/Controllers/V1/TokenController.cs index b8775c05b..66cc66acf 100644 --- a/src/Ombi/Controllers/V1/TokenController.cs +++ b/src/Ombi/Controllers/V1/TokenController.cs @@ -16,6 +16,8 @@ using Ombi.Models.External; using Ombi.Models.Identity; using Ombi.Store.Entities; using Ombi.Store.Repository; +using Ombi.Core.Settings; +using Ombi.Settings.Settings.Models; namespace Ombi.Controllers.V1 { @@ -25,13 +27,14 @@ namespace Ombi.Controllers.V1 public class TokenController : ControllerBase { public TokenController(OmbiUserManager um, IOptions ta, ITokenRepository token, - IPlexOAuthManager oAuthManager, ILogger logger) + IPlexOAuthManager oAuthManager, ILogger logger, ISettingsService auth) { _userManager = um; _tokenAuthenticationOptions = ta.Value; _token = token; _plexOAuthManager = oAuthManager; _log = logger; + _authSettings = auth; } private readonly TokenAuthentication _tokenAuthenticationOptions; @@ -39,6 +42,7 @@ namespace Ombi.Controllers.V1 private readonly OmbiUserManager _userManager; private readonly IPlexOAuthManager _plexOAuthManager; private readonly ILogger _log; + private readonly ISettingsService _authSettings; /// /// Gets the token. @@ -283,25 +287,31 @@ namespace Ombi.Controllers.V1 // TODO // var ombiSettings = await repo.GetSettingsAsync(); // END TODO + var authSettings = await _authSettings.GetSettingsAsync(); + _log.LogInformation("Logging with header: " + authSettings.HeaderAuthVariable); + if (authSettings.HeaderAuthVariable != null) + { + if (Request.HttpContext?.Request?.Headers != null && Request.HttpContext.Request.Headers.ContainsKey(authSettings.HeaderAuthVariable)) + { + username = Request.HttpContext.Request.Headers[authSettings.HeaderAuthVariable].ToString(); + // Check if user exists + var user = await _userManager.FindByNameAsync(username); + if (user == null) + { + return new UnauthorizedResult(); + } - if (Request.HttpContext?.Request?.Headers != null && Request.HttpContext.Request.Headers.ContainsKey("X-Remote-User")) - { - username = Request.HttpContext.Request.Headers["X-Remote-User"].ToString(); - - // Check if user exists - var user = await _userManager.FindByNameAsync(username); - if (user == null) + return await CreateToken(true, user); + } + else { return new UnauthorizedResult(); } - - return await CreateToken(true, user); - } + } else { return new UnauthorizedResult(); - } } } From 5ddda3c39e408eb9208db15081774e083e5fdb2f Mon Sep 17 00:00:00 2001 From: Francesco Servida Date: Tue, 15 Feb 2022 23:27:02 +0100 Subject: [PATCH 3/6] Implemented Settings in Model --- src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs b/src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs index f6736e7c5..a72708123 100644 --- a/src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs +++ b/src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs @@ -13,5 +13,8 @@ namespace Ombi.Settings.Settings.Models public bool RequireNonAlphanumeric { get; set; } public bool RequireUppercase { get; set; } public bool EnableOAuth { get; set; } // Plex OAuth + public bool EnableHeaderAuth { get; set; } // Header SSO + public string HeaderAuthVariable { get; set; } // Header SSO + } } \ No newline at end of file From df2092d5e39d0707541af015934f6836d865a67c Mon Sep 17 00:00:00 2001 From: Francesco Servida Date: Tue, 15 Feb 2022 23:40:23 +0100 Subject: [PATCH 4/6] Implemented check for header auth enabled also in backend --- src/Ombi/Controllers/V1/TokenController.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Ombi/Controllers/V1/TokenController.cs b/src/Ombi/Controllers/V1/TokenController.cs index 66cc66acf..67f0e1189 100644 --- a/src/Ombi/Controllers/V1/TokenController.cs +++ b/src/Ombi/Controllers/V1/TokenController.cs @@ -283,13 +283,9 @@ namespace Ombi.Controllers.V1 { string username = null; - // Check if Header Auth is enabled and Proxy IP is trusted - // TODO - // var ombiSettings = await repo.GetSettingsAsync(); - // END TODO var authSettings = await _authSettings.GetSettingsAsync(); _log.LogInformation("Logging with header: " + authSettings.HeaderAuthVariable); - if (authSettings.HeaderAuthVariable != null) + if (authSettings.HeaderAuthVariable != null && authSettings.EnableHeaderAuth) { if (Request.HttpContext?.Request?.Headers != null && Request.HttpContext.Request.Headers.ContainsKey(authSettings.HeaderAuthVariable)) { From fdb54989b0767fa90a210655482d61d7bd24d5df Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 2 Mar 2022 20:15:56 +0000 Subject: [PATCH 5/6] refactor: :recycle: Small changes around the header auth --- .../Settings/Models/AuthenticationSettings.cs | 1 - .../ClientApp/src/app/login/login.component.ts | 14 +++++++++----- src/Ombi/Controllers/V1/TokenController.cs | 6 ++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs b/src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs index a72708123..ed2775480 100644 --- a/src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs +++ b/src/Ombi.Settings/Settings/Models/AuthenticationSettings.cs @@ -15,6 +15,5 @@ namespace Ombi.Settings.Settings.Models public bool EnableOAuth { get; set; } // Plex OAuth public bool EnableHeaderAuth { get; set; } // Header SSO public string HeaderAuthVariable { get; set; } // Header SSO - } } \ No newline at end of file diff --git a/src/Ombi/ClientApp/src/app/login/login.component.ts b/src/Ombi/ClientApp/src/app/login/login.component.ts index 132554f4f..f6f519191 100644 --- a/src/Ombi/ClientApp/src/app/login/login.component.ts +++ b/src/Ombi/ClientApp/src/app/login/login.component.ts @@ -106,7 +106,10 @@ export class LoginComponent implements OnDestroy, OnInit { this.settingsService .getAuthentication() - .subscribe((x) => { this.authenticationSettings = x; this.headerAuth(); }); + .subscribe((x) => { + this.authenticationSettings = x; + this.headerAuth(); + }); this.settingsService.getClientId().subscribe((x) => (this.clientId = x)); this.images.getRandomBackground().subscribe((x) => { this.background = this.sanitizer.bypassSecurityTrustStyle( @@ -255,10 +258,9 @@ export class LoginComponent implements OnDestroy, OnInit { } public headerAuth() { - if (this.authenticationSettings.enableHeaderAuth) { - this.authService.headerAuth().subscribe( - (x) => { + this.authService.headerAuth().subscribe({ + next: (x) => { this.store.save("id_token", x.access_token); if (this.authService.loggedIn()) { @@ -270,11 +272,13 @@ export class LoginComponent implements OnDestroy, OnInit { }); } }, - (err) => { + error: (e) => { this.notify.open(this.errorBody, "OK", { duration: 3000000, }); + console.error(e); } + } ); } } diff --git a/src/Ombi/Controllers/V1/TokenController.cs b/src/Ombi/Controllers/V1/TokenController.cs index 67f0e1189..3a409c206 100644 --- a/src/Ombi/Controllers/V1/TokenController.cs +++ b/src/Ombi/Controllers/V1/TokenController.cs @@ -147,7 +147,6 @@ namespace Ombi.Controllers.V1 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(StartupSingleton.Instance.SecurityKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); - var token = new JwtSecurityToken( claims: claims, expires: rememberMe ? DateTime.Now.AddYears(1) : DateTime.Now.AddDays(7), @@ -279,17 +278,16 @@ namespace Ombi.Controllers.V1 [HttpPost("header_auth")] [ProducesResponseType(401)] + [ProducesResponseType(200)] public async Task HeaderAuth() { - string username = null; - var authSettings = await _authSettings.GetSettingsAsync(); _log.LogInformation("Logging with header: " + authSettings.HeaderAuthVariable); if (authSettings.HeaderAuthVariable != null && authSettings.EnableHeaderAuth) { if (Request.HttpContext?.Request?.Headers != null && Request.HttpContext.Request.Headers.ContainsKey(authSettings.HeaderAuthVariable)) { - username = Request.HttpContext.Request.Headers[authSettings.HeaderAuthVariable].ToString(); + var username = Request.HttpContext.Request.Headers[authSettings.HeaderAuthVariable].ToString(); // Check if user exists var user = await _userManager.FindByNameAsync(username); From bf3911af76696fd4d3afb6ae70a072c8890e544d Mon Sep 17 00:00:00 2001 From: tidusjar Date: Wed, 2 Mar 2022 20:21:07 +0000 Subject: [PATCH 6/6] refactor: validators --- .../authentication.component.html | 37 +------------------ .../authentication.component.ts | 12 +++++- 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.html b/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.html index bde67e1c7..5960c79f7 100644 --- a/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.html +++ b/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.html @@ -25,48 +25,13 @@ -
+
-
diff --git a/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.ts b/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.ts index 386711c4f..100a502b3 100644 --- a/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.ts +++ b/src/Ombi/ClientApp/src/app/settings/authentication/authentication.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from "@angular/core"; -import { FormBuilder, FormGroup } from "@angular/forms"; +import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { NotificationService } from "../../services"; import { SettingsService } from "../../services"; @@ -29,7 +29,17 @@ export class AuthenticationComponent implements OnInit { enableHeaderAuth: [x.enableHeaderAuth], headerAuthVariable: [x.headerAuthVariable], }); + this.form.controls.enableHeaderAuth.valueChanges.subscribe(x => { + if (x) { + this.form.get("headerAuthVariable").setValidators(Validators.required); + } else { + this.form.get("headerAuthVariable").clearValidators(); + } + this.form.get("headerAuthVariable").updateValueAndValidity(); + }); }); + + } public onSubmit(form: FormGroup) {