-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added client_secrets.json to ignore files * Added Google OAuth to dependencies * Created Initial Structure of Backend Authorization * Removed unnecessary print statements * Moved OAuth business logic to service * Endpoint now exists to log a user out * Removed accidental duplicate claim * OAuth controller now redirects to frontend * Added whoami endpoint for frontend * Added credentials to cors policy * Simplified Claims Schema * GetUserClaims does not accept null AuthenticateResult now * Added whoami auth endpoint * Side-Nav logs out from backend * Login flow now redirects to backend * Removed local GoogleOAuthProvider * Added auth url backend to frontend env * Logout endpoint now works even when a user is not logged in * Added logout redirection with path host validation * Continue as Guest now logs out and redirects to loggedIn * Documentation on whoami route * Added dotenv support * Added app/ directory to gitignore * Added documentation about google cloud project * Docker now supports google environment variables and added documentation
- Loading branch information
Showing
22 changed files
with
331 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
using System.Security.Claims; | ||
using Chemistry_Cafe_API.Models; | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.AspNetCore.Authentication.Google; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.IdentityModel.Protocols.Configuration; | ||
|
||
namespace Chemistry_Cafe_API.Controllers | ||
{ | ||
/// <summary> | ||
/// Controls routes related to Google OAuth 2.0 authentication | ||
/// </summary> | ||
[Route("/auth/google")] | ||
public class GoogleOAuthController : Controller | ||
{ | ||
private readonly GoogleOAuthService _googleOAuthService; | ||
private readonly IConfiguration _configuration; | ||
public GoogleOAuthController(IConfiguration configuration, GoogleOAuthService googleOAuthService) | ||
{ | ||
_googleOAuthService = googleOAuthService; | ||
_configuration = configuration; | ||
} | ||
|
||
/// <summary> | ||
/// Route which the user redirects to a google authentication page | ||
/// </summary> | ||
[HttpGet("login")] | ||
public IActionResult LoginRedirect() | ||
{ | ||
AuthenticationProperties authProperties = new AuthenticationProperties { RedirectUri = "/auth/google/authenticate" }; | ||
return new ChallengeResult(GoogleDefaults.AuthenticationScheme, authProperties); | ||
} | ||
|
||
/// <summary> | ||
/// Route that user will be redirected to after signing in with Google OAuth. | ||
/// This route essentially sets a user's information in a cookie. | ||
/// </summary> | ||
[HttpGet("authenticate")] | ||
public async Task<IActionResult> GoogleResponse() | ||
{ | ||
AuthenticateResult result = await HttpContext.AuthenticateAsync("External"); | ||
if (!result.Succeeded) | ||
{ | ||
return BadRequest("Google OAuth Http Response did not succeed"); | ||
} | ||
|
||
ClaimsPrincipal? claimsIdentity = _googleOAuthService.GetUserClaims(result); | ||
if (claimsIdentity == null) | ||
{ | ||
return BadRequest("Invalid Credentials Passed"); | ||
} | ||
|
||
await HttpContext.SignInAsync("Application", claimsIdentity); | ||
string redirectUrl = (_configuration["FrontendHost"] ?? throw new InvalidConfigurationException("")) + "/LoggedIn"; | ||
return Redirect(redirectUrl); | ||
} | ||
|
||
/// <summary> | ||
/// Removes all authentication cookies and signs a user out of the backend application | ||
/// </summary> | ||
[HttpGet("logout")] | ||
public async Task<IActionResult> Logout(string? returnUrl) | ||
{ | ||
string frontendHost = _configuration["FrontendHost"] ?? throw new InvalidConfigurationException("'FrontendHost' key not set in appsettings"); | ||
// Ensure the redirect url is | ||
if (returnUrl == null || returnUrl.Equals("")) | ||
{ | ||
returnUrl = frontendHost; | ||
} | ||
else if (!Url.IsLocalUrl(returnUrl) && !returnUrl.StartsWith(frontendHost)) | ||
{ | ||
return BadRequest("Invalid returnUrl argument. Must be within application scope."); | ||
} | ||
|
||
await HttpContext.SignOutAsync("Application"); | ||
|
||
var request = HttpContext.Request; | ||
var cookies = request.Cookies; | ||
if (cookies.Count > 0) | ||
{ | ||
foreach (var cookie in cookies) | ||
{ | ||
if (cookie.Key.Contains(".AspNetCore.") || cookie.Key.Contains("Microsoft.Authentication")) | ||
{ | ||
Response.Cookies.Delete(cookie.Key); | ||
} | ||
} | ||
} | ||
|
||
return Redirect(returnUrl); | ||
} | ||
|
||
/// <summary> | ||
/// Gives the user information on themselves | ||
/// </summary> | ||
[HttpGet("whoami")] | ||
public UserClaims GetUserClaims() | ||
{ | ||
ClaimsIdentity? claimsIdentity = HttpContext.User.Identity as ClaimsIdentity; | ||
if (claimsIdentity == null) | ||
{ | ||
return new UserClaims | ||
{ | ||
NameIdentifier = null, | ||
EmailClaim = null, | ||
}; | ||
} | ||
|
||
return new UserClaims | ||
{ | ||
NameIdentifier = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier)?.Value, | ||
EmailClaim = claimsIdentity.FindFirst(ClaimTypes.Email)?.Value | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using System.Text.Json.Serialization; | ||
|
||
namespace Chemistry_Cafe_API.Models | ||
{ | ||
/// <summary> | ||
/// Represents a user's authentication claims. | ||
/// These are set in the user's cookies when the user logs in. | ||
/// </summary> | ||
public partial class UserClaims | ||
{ | ||
[JsonPropertyName("nameId")] | ||
public string? NameIdentifier { get; set; } | ||
|
||
[JsonPropertyName("email")] | ||
public string? EmailClaim { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
|
||
using System.Security.Claims; | ||
using Microsoft.AspNetCore.Authentication; | ||
|
||
namespace Chemistry_Cafe_API.Controllers | ||
{ | ||
/// <summary> | ||
/// Adapted from: https://blog.rashik.com.np/adding-google-authentication-in-net-core-application-without-identity/ | ||
/// </summary> | ||
public class GoogleOAuthService | ||
{ | ||
/// <summary> | ||
/// Parses an OAuth challenge result and turns them into a user's claims | ||
/// </summary> | ||
/// <param name="authenticateResult">Result of Google OAuth Challenge</param> | ||
/// <returns>ClaimsPrincipal object which holds the user's auth informations</returns> | ||
public ClaimsPrincipal? GetUserClaims(AuthenticateResult authenticateResult) | ||
{ | ||
if (authenticateResult.Principal == null) | ||
{ | ||
return null; | ||
} | ||
|
||
var identityList = authenticateResult.Principal.Identities.ToList(); | ||
if (authenticateResult.Principal != null && identityList.Count > 0) | ||
{ | ||
var identity = identityList[0]; | ||
if (identity.AuthenticationType != null && identity.AuthenticationType.ToLower().Equals("google")) | ||
{ | ||
var claimsIdentity = new ClaimsIdentity("Application"); | ||
var nameIdClaim = authenticateResult.Principal.FindFirst(ClaimTypes.NameIdentifier); // GUID specified by Google | ||
var emailClaim = authenticateResult.Principal.FindFirst(ClaimTypes.Email); | ||
|
||
if (nameIdClaim != null && emailClaim != null) | ||
{ | ||
claimsIdentity.AddClaim(nameIdClaim); | ||
claimsIdentity.AddClaim(emailClaim); | ||
} | ||
else | ||
{ | ||
return null; | ||
} | ||
return new ClaimsPrincipal(claimsIdentity); | ||
} | ||
else | ||
{ | ||
return null; | ||
} | ||
} | ||
return null; | ||
} | ||
} | ||
} |
Oops, something went wrong.