Skip to content

Commit 3276f5d

Browse files
committed
feat: login, general improvements and minor bugs
1 parent 826b7b2 commit 3276f5d

11 files changed

Lines changed: 84 additions & 123 deletions

File tree

src/WebExpress.WebCore.Test/Data/MockIdentityProvider.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using WebExpress.WebCore.WebEndpoint;
2-
using WebExpress.WebCore.WebIdentity;
1+
using WebExpress.WebCore.WebIdentity;
32
using WebExpress.WebCore.WebMessage;
3+
using WebExpress.WebCore.WebPage;
44

55
namespace WebExpress.WebCore.Test.Data
66
{
@@ -84,7 +84,7 @@ public void Logout(IRequest request)
8484
/// An object that represents the response to the login dialog, including authentication results and any
8585
/// relevant status information.
8686
/// </returns>
87-
public IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext initiator, IIdentity identity)
87+
public IResponse CreateAuthenticationPrompt(IRequest request, IPageContext initiator, IIdentity identity)
8888
{
8989
return null;
9090
}
@@ -106,7 +106,7 @@ public IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext i
106106
/// A response representing the forbidden page if this provider can handle the forbidden
107107
/// scenario; otherwise, <c>null</c>.
108108
/// </returns>
109-
public IResponse CreateForbiddenPage(IRequest request, IEndpointContext initiator, IIdentity identity)
109+
public IResponse CreateForbiddenPage(IRequest request, IPageContext initiator, IIdentity identity)
110110
{
111111
return null;
112112
}

src/WebExpress.WebCore.Test/Manager/UnitTestIdentityManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,10 @@ public void Login(string identityName, bool expected)
153153
var identity = MockIdentityFactory.GetIdentity(identityName);
154154

155155
// act
156-
var res = identityManager.Login(request, identity);
156+
var res = identityManager.Login(identity, request);
157157

158158
// validation
159-
Assert.Equal(expected, res);
159+
Assert.Equal(expected, res is not null);
160160
}
161161

162162
/// <summary>
@@ -173,7 +173,7 @@ public void Logout(string identityName)
173173
var identityManager = componentHub.IdentityManager as IdentityManager;
174174
var request = UnitTestFixture.CreateRequestMock();
175175
var identity = MockIdentityFactory.GetIdentity(identityName);
176-
identityManager.Login(request, identity);
176+
identityManager.Login(identity, request);
177177

178178
// act
179179
identityManager.Logout(request);
@@ -197,7 +197,7 @@ public void GetCurrentIdentity(string identityName)
197197
var identityManager = componentHub.IdentityManager as IdentityManager;
198198
var request = UnitTestFixture.CreateRequestMock();
199199
var identity = MockIdentityFactory.GetIdentity(identityName);
200-
identityManager.Login(request, identity);
200+
identityManager.Login(identity, request);
201201

202202
// act
203203
var res = identityManager.GetCurrentIdentity(request);

src/WebExpress.WebCore.Test/TestRenderContext.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class TestRenderContext : IRenderContext
1717
/// <summary>
1818
/// Gets the page context.
1919
/// </summary>
20-
public IPageContext PageContext { get; protected set; }
20+
public WebPage.IPageContext PageContext { get; protected set; }
2121

2222
/// <summary>
2323
/// Gets the request.
@@ -30,7 +30,7 @@ public class TestRenderContext : IRenderContext
3030
/// <param name="endpoint">The endpoint associated with the rendering context.</param>
3131
/// <param name="pageContext">>The page context.</param>
3232
/// <param name="request">The request associated with the rendering context.</param>
33-
public TestRenderContext(IEndpoint endpoint, IPageContext pageContext, IRequest request)
33+
public TestRenderContext(IEndpoint endpoint, WebPage.IPageContext pageContext, IRequest request)
3434
{
3535
Endpoint = endpoint;
3636
PageContext = pageContext;

src/WebExpress.WebCore/HttpServer.cs

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using WebExpress.WebCore.WebEndpoint;
2424
using WebExpress.WebCore.WebLog;
2525
using WebExpress.WebCore.WebMessage;
26+
using WebExpress.WebCore.WebPage;
2627
using WebExpress.WebCore.WebParameter;
2728
using WebExpress.WebCore.WebSitemap;
2829
using WebExpress.WebCore.WebSocket;
@@ -495,8 +496,7 @@ private static IResponse CreateStatusPage<TResponse>(string message, IRequest re
495496
var applicationManager = WebEx.ComponentHub.ApplicationManager;
496497
var route = new RouteEndpoint(request.Uri.PathSegments)?.ToString();
497498
var applicationContext = applicationManager.Applications
498-
.Where(x => route.StartsWith(x.Route.ToString()))
499-
.FirstOrDefault();
499+
.FirstOrDefault(x => route.StartsWith(x.Route.ToString()));
500500

501501
if (searchResult != null)
502502
{
@@ -647,23 +647,16 @@ public async Task ProcessRequestAsync(IHttpContext httpContext)
647647
return;
648648
}
649649

650-
// try to authenticate if no identity exists
651-
if (identity is null)
652-
{
653-
identity = _componentHub.IdentityManager.Authenticate(httpContext.Request, applicationContext);
654-
_componentHub.IdentityManager.Login(httpContext.Request, identity);
655-
}
656-
657650
// check again
658651
if (!_componentHub.IdentityManager.CheckAccess(identity, searchResult.EndpointContext))
659652
{
660653
// if the user is authenticated but lacks the required permissions, show the forbidden page
661-
if (identity is not null)
654+
if (identity is not null && searchResult.EndpointContext is IPageContext)
662655
{
663656
var forbiddenResponse = _componentHub.IdentityManager.CreateForbiddenResponse
664657
(
665658
httpContext.Request,
666-
searchResult.EndpointContext,
659+
searchResult.EndpointContext as IPageContext,
667660
identity
668661
);
669662

@@ -672,19 +665,47 @@ public async Task ProcessRequestAsync(IHttpContext httpContext)
672665
await responseSender.SendAsync(httpContext, forbiddenResponse);
673666
return;
674667
}
668+
else
669+
{
670+
forbiddenResponse = CreateStatusPage<ResponseForbidden>
671+
(
672+
new StatusMessage("You do not have permission to access this resource.").Message,
673+
httpContext.Request,
674+
searchResult
675+
);
676+
677+
await responseSender.SendAsync(httpContext, forbiddenResponse);
678+
return;
679+
}
675680
}
681+
else if (identity is not null)
682+
{
683+
var forbiddenResponse = new ResponseForbidden(new StatusMessage("You do not have permission to access this resource."));
676684

677-
// if the user is not authenticated, show the login prompt
678-
var loginResponse = _componentHub.IdentityManager.CreateAuthenticationPrompt
679-
(
680-
httpContext.Request,
681-
searchResult.EndpointContext,
682-
identity
683-
);
685+
await responseSender.SendAsync(httpContext, forbiddenResponse);
686+
return;
687+
}
688+
else if (searchResult.EndpointContext is IPageContext pageContext)
689+
{
690+
// if the user is not authenticated, show the login prompt
691+
var loginResponse = _componentHub.IdentityManager.CreateAuthenticationPrompt
692+
(
693+
httpContext.Request,
694+
searchResult.EndpointContext as IPageContext,
695+
identity
696+
);
684697

685-
if (loginResponse is not null)
698+
if (loginResponse is not null)
699+
{
700+
await responseSender.SendAsync(httpContext, loginResponse);
701+
return;
702+
}
703+
}
704+
else
686705
{
687-
await responseSender.SendAsync(httpContext, loginResponse);
706+
var unauthorizedResponse = new ResponseUnauthorized(new StatusMessage("Authentication required. Provide a valid access token."));
707+
708+
await responseSender.SendAsync(httpContext, unauthorizedResponse);
688709
return;
689710
}
690711
}

src/WebExpress.WebCore/WebIdentity/IIdentityManager.cs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using WebExpress.WebCore.WebComponent;
55
using WebExpress.WebCore.WebEndpoint;
66
using WebExpress.WebCore.WebMessage;
7+
using WebExpress.WebCore.WebPage;
8+
using WebExpress.WebCore.WebSession.Model;
79

810
namespace WebExpress.WebCore.WebIdentity
911
{
@@ -13,8 +15,8 @@ namespace WebExpress.WebCore.WebIdentity
1315
public interface IIdentityManager : IComponentManager
1416
{
1517
/// <summary>
16-
/// Returns all permissions.
17-
/// </Gets>
18+
/// Gets all permissions.
19+
/// </summary>
1820
IEnumerable<IIdentityPermissionContext> Permissions { get; }
1921

2022
/// <summary>
@@ -39,7 +41,7 @@ public interface IIdentityManager : IComponentManager
3941
/// An object that represents the response to the login dialog, including authentication results and any
4042
/// relevant status information.
4143
/// </returns>
42-
IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext initiator, IIdentity identity = null);
44+
IResponse CreateAuthenticationPrompt(IRequest request, IPageContext initiator, IIdentity identity = null);
4345

4446
/// <summary>
4547
/// Creates a forbidden response page for the specified request when the authenticated
@@ -59,29 +61,15 @@ public interface IIdentityManager : IComponentManager
5961
/// A response representing the forbidden page if a registered identity provider can handle the
6062
/// forbidden scenario; otherwise, <c>null</c>.
6163
/// </returns>
62-
IResponse CreateForbiddenResponse(IRequest request, IEndpointContext initiator, IIdentity identity);
63-
64-
/// <summary>
65-
/// Attempts to authenticate the specified request within the given application context.
66-
/// </summary>
67-
/// <param name="request">
68-
/// The request to be authenticated. Must not be null.
69-
/// </param>
70-
/// <param name="applicationContext">
71-
/// The application context in which the authentication is performed. Must not be null.
72-
/// </param>
73-
/// <returns>
74-
/// An identity representing the authenticated user if authentication is successful; otherwise, null.
75-
/// </returns>
76-
IIdentity Authenticate(IRequest request, IApplicationContext applicationContext);
64+
IResponse CreateForbiddenResponse(IRequest request, IPageContext initiator, IIdentity identity);
7765

7866
/// <summary>
7967
/// Login an identity.
8068
/// </summary>
81-
/// <param name="request">The request.</param>
8269
/// <param name="identity">The identity.</param>
83-
/// <returns>True if successful, false otherwise.</returns>
84-
bool Login(IRequest request, IIdentity identity);
70+
/// <param name="request">The request.</param>
71+
/// <returns>The session of the logged-in identity, or null if the login process failed.</returns>
72+
Session Login(IIdentity identity, IRequest request);
8573

8674
/// <summary>
8775
/// Logout an identity.

src/WebExpress.WebCore/WebIdentity/IIdentityProvider.cs

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System.Collections.Generic;
2-
using WebExpress.WebCore.WebEndpoint;
32
using WebExpress.WebCore.WebMessage;
3+
using WebExpress.WebCore.WebPage;
44

55
namespace WebExpress.WebCore.WebIdentity
66
{
@@ -20,26 +20,6 @@ public interface IIdentityProvider
2020
/// </summary>
2121
IEnumerable<IIdentityGroup> GetGroups();
2222

23-
/// <summary>
24-
/// Authenticates the specified request and returns the associated identity.
25-
/// </summary>
26-
/// <param name="request">
27-
/// The request to authenticate. Cannot be null.
28-
/// </param>
29-
/// <returns>
30-
/// An identity representing the authenticated user if authentication is successful; otherwise, null.
31-
/// </returns>
32-
IIdentity Authenticate(IRequest request);
33-
34-
/// <summary>
35-
/// Logs out the specified request by clearing any authentication state
36-
/// managed by this identity provider.
37-
/// </summary>
38-
/// <param name="request">
39-
/// The request whose authentication state should be cleared. Cannot be null.
40-
/// </param>
41-
void Logout(IRequest request);
42-
4323
/// <summary>
4424
/// Displays a login dialog using the specified request and identity information.
4525
/// </summary>
@@ -57,7 +37,7 @@ public interface IIdentityProvider
5737
/// An object that represents the response to the login dialog, including authentication results and any
5838
/// relevant status information.
5939
/// </returns>
60-
IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext initiator, IIdentity identity);
40+
IResponse CreateAuthenticationPrompt(IRequest request, IPageContext initiator, IIdentity identity);
6141

6242
/// <summary>
6343
/// Creates a forbidden response page for the specified request when the authenticated
@@ -77,6 +57,6 @@ public interface IIdentityProvider
7757
/// A response representing the forbidden page if this provider can handle the forbidden
7858
/// scenario; otherwise, <c>null</c>.
7959
/// </returns>
80-
IResponse CreateForbiddenPage(IRequest request, IEndpointContext initiator, IIdentity identity);
60+
IResponse CreateForbiddenPage(IRequest request, IPageContext initiator, IIdentity identity);
8161
}
8262
}

src/WebExpress.WebCore/WebIdentity/IdentityManager.cs

Lines changed: 13 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using WebExpress.WebCore.WebEndpoint;
1313
using WebExpress.WebCore.WebIdentity.Model;
1414
using WebExpress.WebCore.WebMessage;
15+
using WebExpress.WebCore.WebPage;
1516
using WebExpress.WebCore.WebPlugin;
1617
using WebExpress.WebCore.WebSession.Model;
1718

@@ -385,7 +386,7 @@ private void OnAddApplication(object sender, IApplicationContext e)
385386
/// An object that represents the response to the login dialog, including authentication results
386387
/// and any relevant status information.
387388
/// </returns>
388-
public IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext initiator, IIdentity identity = null)
389+
public IResponse CreateAuthenticationPrompt(IRequest request, IPageContext initiator, IIdentity identity = null)
389390
{
390391
if (_identityProviders.TryGetValue(initiator?.ApplicationContext, out var list))
391392
{
@@ -415,7 +416,7 @@ public IResponse CreateAuthenticationPrompt(IRequest request, IEndpointContext i
415416
/// A response representing the forbidden page if a registered identity provider can handle the
416417
/// forbidden scenario; otherwise, <c>null</c>.
417418
/// </returns>
418-
public IResponse CreateForbiddenResponse(IRequest request, IEndpointContext initiator, IIdentity identity)
419+
public IResponse CreateForbiddenResponse(IRequest request, IPageContext initiator, IIdentity identity)
419420
{
420421
if (_identityProviders.TryGetValue(initiator?.ApplicationContext, out var list))
421422
{
@@ -434,48 +435,29 @@ public IResponse CreateForbiddenResponse(IRequest request, IEndpointContext init
434435
return null;
435436
}
436437

437-
/// <summary>
438-
/// Attempts to authenticate the specified request within the given application context.
439-
/// </summary>
440-
/// <param name="request">The request to be authenticated. Must not be null.</param>
441-
/// <param name="applicationContext">The application context in which the authentication is performed. Must not be null.</param>
442-
/// <returns>An identity representing the authenticated user if authentication is successful; otherwise, null.</returns>
443-
public IIdentity Authenticate(IRequest request, IApplicationContext applicationContext)
444-
{
445-
if (_identityProviders.TryGetValue(applicationContext, out var list))
446-
{
447-
foreach (var provider in list)
448-
{
449-
var identity = provider.Authenticate(request);
450-
451-
if (identity is not null)
452-
{
453-
return identity;
454-
}
455-
}
456-
}
457-
458-
return null;
459-
}
460-
461438
/// <summary>
462439
/// Login an identity.
463440
/// </summary>
464-
/// <param name="request">The request.</param>
465441
/// <param name="identity">The identity.</param>
466-
/// <returns>True if successful, false otherwise.</returns>
467-
public bool Login(IRequest request, IIdentity identity)
442+
/// <param name="request">The request.</param>
443+
/// <returns>The session of the logged-in identity, or null if the login process failed.</returns>
444+
public Session Login(IIdentity identity, IRequest request)
468445
{
469446
if (identity is null)
470447
{
471-
return false;
448+
return null;
472449
}
473450

474451
var session = _componentHub.SessionManager.GetSession(request);
475452
var authentification = session.GetOrCreateProperty<SessionPropertyAuthentification>(identity);
476453

477454
// verify that the identity was correctly bound to the session
478-
return authentification.Identity == identity;
455+
if (authentification.Identity != identity)
456+
{
457+
return null;
458+
}
459+
460+
return session;
479461
}
480462

481463
/// <summary>
@@ -484,15 +466,6 @@ public bool Login(IRequest request, IIdentity identity)
484466
/// <param name="request">The request.</param>
485467
public void Logout(IRequest request)
486468
{
487-
// notify all registered identity providers so they can clear their own state
488-
foreach (var list in _identityProviders.Values)
489-
{
490-
foreach (var provider in list)
491-
{
492-
provider.Logout(request);
493-
}
494-
}
495-
496469
var session = _componentHub.SessionManager.GetSession(request);
497470
session.RemoveProperty<SessionPropertyAuthentification>();
498471
}

0 commit comments

Comments
 (0)