Skip to content

Commit

Permalink
🔒 SSO is now working
Browse files Browse the repository at this point in the history
  • Loading branch information
danielmackay committed Nov 4, 2024
1 parent 1b00b0a commit fff2249
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 52 deletions.
33 changes: 25 additions & 8 deletions src/WebUI/Common/Identity/ICurrentUserService.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
namespace WebUI.Common.Identity;
using Microsoft.Graph.Models;
using System.Security.Claims;

namespace WebUI.Common.Identity;

public interface ICurrentUserService
{
string UserId { get; }

string AccessToken { get; }
string FirstName { get; }
string LastName { get; }
string UserName { get; }

void UpdateAccessToken(string token);
void UpdateName(string firstName, string lastName);
Expand All @@ -18,9 +20,7 @@ public class CurrentUserService : ICurrentUserService

public string AccessToken { get; private set; } = string.Empty;

public string FirstName { get; private set; } = string.Empty;

public string LastName { get; private set; } = string.Empty;
public string UserName { get; private set; } = string.Empty;

public void UpdateAccessToken(string token)
{
Expand All @@ -34,7 +34,24 @@ public void UpdateName(string firstName, string lastName)
ArgumentException.ThrowIfNullOrWhiteSpace(firstName);
ArgumentException.ThrowIfNullOrWhiteSpace(lastName);

FirstName = firstName;
LastName = lastName;
UserName = $"{firstName} {lastName}";
}
}

public class OAuthCurrentUserService : ICurrentUserService
{
public string UserId { get; }
public string AccessToken { get; } = string.Empty;
public string UserName { get; }

public void UpdateAccessToken(string token) => throw new NotImplementedException();

public void UpdateName(string firstName, string lastName) => throw new NotImplementedException();

public OAuthCurrentUserService(IHttpContextAccessor httpContextAccessor)
{
UserId = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier) ?? string.Empty;
UserName = httpContextAccessor.HttpContext?.User?.FindFirstValue("Name") ?? string.Empty;
UserName = UserName.TrimEnd(" [SSW]");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public GraphService(
GraphServiceClientFactory factory)
{
_logger = logger;
_graphServiceClient = factory.CreateWithAccessToken();
_graphServiceClient = factory.CreateDefault();
}

// public async Task<List<TodoTaskList>?> GetTodoLists()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ public class GraphServiceClientFactory
{
private readonly ICurrentUserService _currentUserService;
private readonly IServiceProvider _serviceProvider;

// TODO: Read from config
private readonly string _clientId = "2407f45c-4141-4484-8fc5-ce61327519d9";
private readonly string _tenantId = "ac2f7c34-b935-48e9-abdc-11e5d4fcb2b0";
private readonly string _redirectUri = "http://localhost:5001"; // Must match redirect URI in app registration
private readonly string[] _scopes = new[] { "User.Read" };

public GraphServiceClientFactory(ICurrentUserService currentUserService, IServiceProvider serviceProvider)
{
_currentUserService = currentUserService;
_serviceProvider = serviceProvider;
}

public GraphServiceClient Create()
public GraphServiceClient CreateDefault()
{
return _serviceProvider.GetRequiredService<GraphServiceClient>();
}
Expand All @@ -33,8 +36,6 @@ public GraphServiceClient CreateWithAccessToken()

public GraphServiceClient CreateWithDeviceCodeFlow()
{
var scopes = new[] { "User.Read" };

var options = new DeviceCodeCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
Expand All @@ -53,7 +54,7 @@ public GraphServiceClient CreateWithDeviceCodeFlow()
// https://learn.microsoft.com/dotnet/api/azure.identity.devicecodecredential
var deviceCodeCredential = new DeviceCodeCredential(options);

var graphClient = new GraphServiceClient(deviceCodeCredential, scopes);
var graphClient = new GraphServiceClient(deviceCodeCredential, _scopes);

return graphClient;
}
Expand Down
5 changes: 2 additions & 3 deletions src/WebUI/Features/DailyScrum/Queries/GetDailyScrumQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,11 @@ private async Task<List<ProjectViewModel>> GetProjects(DateOnly date)

private EmailViewModel GetEmail()
{
var firstName = _currentUserService.FirstName;
var lastName = _currentUserService.LastName;
var userName = _currentUserService.UserName;

return new EmailViewModel
{
Subject = $"{firstName} {lastName} - Daily Scrum",
Subject = $"{userName} - Daily Scrum",
To = new EmailParticipantViewModel
{
Name = "SSWBenchMasters",
Expand Down
31 changes: 16 additions & 15 deletions src/WebUI/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using System.Reflection;
Expand All @@ -12,18 +11,18 @@

var initialScopes = builder.Configuration.GetSection("DownstreamApi:Scopes").Get<string[]>();

// builder.Services
// .AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
// .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
// .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
// .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
// .AddInMemoryTokenCaches();
//
// builder.Services.AddAuthorization(options =>
// {
// // By default, all incoming requests will be authorized according to the default policy.
// options.FallbackPolicy = options.DefaultPolicy;
// });
builder.Services
.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();

builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});

builder.Services
.AddRazorPages()
Expand All @@ -32,7 +31,8 @@
// App Services
builder.Services.ConfigureFeatures(builder.Configuration, appAssembly);
builder.Services.AddMediatR();
builder.Services.AddSingleton<ICurrentUserService, CurrentUserService>();
// builder.Services.AddSingleton<ICurrentUserService, CurrentUserService>();
builder.Services.AddScoped<ICurrentUserService, OAuthCurrentUserService>();
builder.Services.AddScoped<GraphServiceClientFactory>();

var app = builder.Build();
Expand All @@ -47,7 +47,8 @@

app.UseRouting();

// app.UseAuthorization();
app.UseAuthentication();
app.UseAuthorization();

app.MapStaticAssets();
app.MapRazorPages()
Expand Down
24 changes: 6 additions & 18 deletions src/WebUI/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
{
/*
The following identity settings need to be configured
before the project can be successfully executed.
For more info see https://aka.ms/dotnet-template-ms-identity-platform
*/
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "qualified.domain.name",
Expand All @@ -15,21 +10,14 @@
"CallbackPath": "/signin-oidc"
},
"DownstreamApi": {
/*
'Scopes' contains scopes of the Web API you want to call. This can be:
- a scope for a V2 application (for instance api:b3682cc7-8b30-4bd2-aaba-080c6bf0fd31/access_as_user)
- a scope corresponding to a V1 application (for instance <App ID URI>/.default, where <App ID URI> is the
App ID URI of a legacy v1 Web application
Applications are registered in the https:portal.azure.com portal.
*/
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": [
"user.read",
// "tasks.read",
// "mailboxitem.read",
// "mailboxfolder.read",
// "mail.readbasic",
"mail.readbasic"
"mail.read",
"mail.readbasic",
"mailboxfolder.read",
"mailboxitem.read",
"tasks.read",
"user.read"
]
},
"Logging": {
Expand Down
5 changes: 2 additions & 3 deletions tests/UnitTests/UpdateAccessTokenCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ public void Handle_GivenValidAccessToken_ShouldSetFirstNameAndLastName()

sut.Handle(new UpdateAccessTokenCommand(token), CancellationToken.None);

currentUserService.FirstName.Should().Be("Daniel");
currentUserService.LastName.Should().Be("Mackay");
currentUserService.UserName.Should().Be("Daniel Mackay");
}
}
}

0 comments on commit fff2249

Please sign in to comment.