Skip to content

Commit 08d299f

Browse files
Merge pull request #13 from webexpress-framework/copilot/develop-identity-model
Implement complete identity model with default group, standard policies, and enhanced interfaces
2 parents 41d6048 + cd6680e commit 08d299f

12 files changed

Lines changed: 216 additions & 6 deletions

File tree

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

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,5 +207,73 @@ public void GetCurrentIdentity(string identityName, string password)
207207

208208
Assert.Equal(identity, res);
209209
}
210+
211+
/// <summary>
212+
/// Test that the AllGroup is not null and has the expected default properties.
213+
/// </summary>
214+
[Fact]
215+
public void AllGroupExists()
216+
{
217+
// arrange
218+
var componentHub = UnitTestFixture.CreateAndRegisterComponentHubMock();
219+
var identityManager = componentHub.IdentityManager;
220+
221+
// act & assert
222+
Assert.NotNull(identityManager.AllGroup);
223+
Assert.Equal("All", identityManager.AllGroup.Name);
224+
Assert.Equal(Guid.Empty, identityManager.AllGroup.Id);
225+
}
226+
227+
/// <summary>
228+
/// Test that the AllGroup has the PublicAccess policy.
229+
/// </summary>
230+
[Fact]
231+
public void AllGroupHasPublicAccessPolicy()
232+
{
233+
// arrange
234+
var componentHub = UnitTestFixture.CreateAndRegisterComponentHubMock();
235+
var identityManager = componentHub.IdentityManager;
236+
237+
// act
238+
var policies = identityManager.AllGroup.Policies;
239+
240+
// assert
241+
Assert.Contains(typeof(PublicAccess).FullName.ToLower(), policies);
242+
}
243+
244+
/// <summary>
245+
/// Test that the IIdentityGroup interface has the Id and Name properties.
246+
/// </summary>
247+
[Fact]
248+
public void IIdentityGroupHasIdAndName()
249+
{
250+
// arrange
251+
var group = MockIdentityFactory.GetIdentityGroup("Admins");
252+
253+
// act & assert
254+
Assert.NotNull(group);
255+
Assert.IsAssignableFrom<IIdentityGroup>(group);
256+
Assert.NotEqual(Guid.Empty, group.Id);
257+
Assert.Equal("Admins", group.Name);
258+
}
259+
260+
/// <summary>
261+
/// Test that the AllGroup has the expected name and contains the PublicAccess policy.
262+
/// </summary>
263+
[Fact]
264+
public void AllGroupHasExpectedProperties()
265+
{
266+
// arrange
267+
var componentHub = UnitTestFixture.CreateAndRegisterComponentHubMock();
268+
var identityManager = componentHub.IdentityManager as IdentityManager;
269+
270+
// act
271+
var allGroup = identityManager.AllGroup;
272+
273+
// assert
274+
Assert.NotNull(allGroup);
275+
Assert.Equal("All", allGroup.Name);
276+
Assert.Contains(typeof(PublicAccess).FullName.ToLower(), allGroup.Policies);
277+
}
210278
}
211279
}

src/WebExpress.WebCore/Internationalization/de

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ identitymanager.registerpermission=Die Berechtigung '{0}' wurde der Anwendung '{
165165
identitymanager.duplicatepermission=Die Berechtigung '{0}' wurde bereits in der Anwendung '{1}' registriert.
166166
identitymanager.registerpolicy=Die Policy '{0}' wurde der Anwendung '{1}' zugewiesen und im Identitymanager registriert.
167167
identitymanager.duplicatepolicy=Die Policy '{0}' wurde bereits in der Anwendung '{1}' registriert.
168+
identitymanager.policy.publicaccess.name=Öffentlicher Zugang
169+
identitymanager.policy.publicaccess.description=Policy für den Zugriff auf öffentliche Ressourcen ohne Authentifizierung.
170+
identitymanager.policy.authenticatedaccess.name=Authentifizierter Zugang
171+
identitymanager.policy.authenticatedaccess.description=Policy für den allgemeinen Zugriff durch authentifizierte Benutzer.
172+
identitymanager.policy.systemaccess.name=Systemzugang
173+
identitymanager.policy.systemaccess.description=Policy für Operationen auf Systemebene wie Installation, Aktualisierung und Wartung der Anwendung.
168174

169175
includemanager.initialization=Der Includemanager wurde initialisiert.
170176
includemanager.addinclude=Die Client-Ressource '{0}' wurde in der Anwendung '{1}' registiert.

src/WebExpress.WebCore/Internationalization/en

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,12 @@ identitymanager.registerpermission=The permission '{0}' has been assigned to the
165165
identitymanager.duplicatepermission=The permission '{0}' has already been registered in the application '{1}'.
166166
identitymanager.registerpolicy=The policy '{0}' has been assigned to the application '{1}' and registered in the identity manager.
167167
identitymanager.duplicatepolicy=The policy '{0}' has already been registered in the application '{1}'.
168+
identitymanager.policy.publicaccess.name=Public Access
169+
identitymanager.policy.publicaccess.description=Policy for accessing public resources without authentication.
170+
identitymanager.policy.authenticatedaccess.name=Authenticated Access
171+
identitymanager.policy.authenticatedaccess.description=Policy for general access by authenticated users.
172+
identitymanager.policy.systemaccess.name=System Access
173+
identitymanager.policy.systemaccess.description=Policy for system-level operations such as installing, updating, and maintaining the application.
168174

169175
includemanager.initialization=The include manager has been initialized.
170176
includemanager.addinclude=The client resource '{0}' has been registered in the application '{1}'.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using WebExpress.WebCore.WebAttribute;
2+
3+
namespace WebExpress.WebCore.WebIdentity
4+
{
5+
/// <summary>
6+
/// Standard policy for general access by authenticated users.
7+
/// </summary>
8+
[Name("webexpress.webcore:identitymanager.policy.authenticatedaccess.name")]
9+
[Description("webexpress.webcore:identitymanager.policy.authenticatedaccess.description")]
10+
public sealed class AuthenticatedAccess : IIdentityPolicy
11+
{
12+
/// <summary>
13+
/// Releases all resources used by the current instance of the class.
14+
/// </summary>
15+
public void Dispose()
16+
{
17+
}
18+
}
19+
}

src/WebExpress.WebCore/WebIdentity/IIdentityGroup.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Collections.Generic;
1+
using System;
2+
using System.Collections.Generic;
23

34
namespace WebExpress.WebCore.WebIdentity
45
{
@@ -7,6 +8,16 @@ namespace WebExpress.WebCore.WebIdentity
78
/// </summary>
89
public interface IIdentityGroup
910
{
11+
/// <summary>
12+
/// Returns the id of the group.
13+
/// </summary>
14+
Guid Id { get; }
15+
16+
/// <summary>
17+
/// Returns the name of the group.
18+
/// </summary>
19+
string Name { get; }
20+
1021
/// <summary>
1122
/// Returns the policies associated with the group.
1223
/// </summary>

src/WebExpress.WebCore/WebIdentity/IIdentityManager.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ public interface IIdentityManager : IComponentManager
2727
/// </summary>
2828
IEnumerable<IIdentity> Identities { get; }
2929

30+
/// <summary>
31+
/// Returns the default "All" group to which every identity automatically belongs.
32+
/// </summary>
33+
IdentityGroupAll AllGroup { get; }
34+
3035
/// <summary>
3136
/// Returns the current signed-in identity.
3237
/// </summary>

src/WebExpress.WebCore/WebIdentity/IIdentityPolicyContext.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using WebExpress.WebCore.WebApplication;
1+
using System;
2+
using WebExpress.WebCore.WebApplication;
23
using WebExpress.WebCore.WebComponent;
34
using WebExpress.WebCore.WebPlugin;
45

@@ -14,6 +15,11 @@ public interface IIdentityPolicyContext : IContext
1415
/// </summary>
1516
IComponentId PolicyId { get; }
1617

18+
/// <summary>
19+
/// Returns the policy type.
20+
/// </summary>
21+
Type Policy { get; }
22+
1723
/// <summary>
1824
/// Returns the associated plugin context.
1925
/// </summary>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
5+
namespace WebExpress.WebCore.WebIdentity
6+
{
7+
/// <summary>
8+
/// Represents the default "All" group to which every identity automatically belongs.
9+
/// </summary>
10+
public class IdentityGroupAll : IIdentityGroup
11+
{
12+
/// <summary>
13+
/// Returns the id of the group.
14+
/// </summary>
15+
public Guid Id { get; } = Guid.Empty;
16+
17+
/// <summary>
18+
/// Returns the name of the group.
19+
/// </summary>
20+
public string Name => "All";
21+
22+
/// <summary>
23+
/// Returns the policies associated with the group.
24+
/// </summary>
25+
public IEnumerable<string> Policies { get; }
26+
27+
/// <summary>
28+
/// Initializes a new instance of the class.
29+
/// </summary>
30+
/// <param name="policies">The policies to associate with the group.</param>
31+
internal IdentityGroupAll(IEnumerable<string> policies)
32+
{
33+
Policies = policies?.ToList() ?? [];
34+
}
35+
}
36+
}

src/WebExpress.WebCore/WebIdentity/IdentityManager.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ public class IdentityManager : IIdentityManager
2727
private readonly IdentityPermissionDictionary _permissionDictionary = [];
2828
private readonly IdentityPolicyDictionary _policyDictionary = [];
2929

30+
/// <summary>
31+
/// Returns the default "All" group to which every identity automatically belongs.
32+
/// </summary>
33+
public IdentityGroupAll AllGroup { get; } = new IdentityGroupAll([typeof(PublicAccess).FullName.ToLower()]);
34+
3035
/// <summary>
3136
/// Returns all permissions.
3237
/// </summary>
@@ -229,7 +234,8 @@ private void Register(IPluginContext pluginContext, IEnumerable<IApplicationCont
229234
{
230235
PluginContext = pluginContext,
231236
ApplicationContext = applicationContext,
232-
PolicyId = id
237+
PolicyId = id,
238+
Policy = policyType
233239
};
234240

235241
if (_policyDictionary.AddPolicyItem
@@ -437,15 +443,18 @@ public bool CheckAccess<T>(IApplicationContext applicationContext, IIdentity ide
437443
}
438444

439445
/// <summary>
440-
/// Checks whether the given identity has the specified permission by evaluating all associated groups.
446+
/// Checks whether the given identity has the specified permission by evaluating all associated groups,
447+
/// including the default "All" group to which every identity automatically belongs.
441448
/// </summary>
442449
/// <param name="applicationContext">The context of the application.</param>
443450
/// <param name="identity">The identity to check.</param>
444451
/// <param name="permission">The permission to check for.</param>
445452
/// <returns>True if any group grants the permission, false otherwise.</returns>
446453
public bool CheckAccess(IApplicationContext applicationContext, IIdentity identity, Type permission)
447454
{
448-
return (identity?.Groups ?? []).Any(group => CheckAccess(applicationContext, group, permission));
455+
var groups = (identity?.Groups ?? []).Append(AllGroup);
456+
457+
return groups.Any(group => CheckAccess(applicationContext, group, permission));
449458
}
450459

451460
/// <summary>

src/WebExpress.WebCore/WebIdentity/IdentityPolicyContext.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using WebExpress.WebCore.WebApplication;
1+
using System;
2+
using WebExpress.WebCore.WebApplication;
23
using WebExpress.WebCore.WebComponent;
34
using WebExpress.WebCore.WebPlugin;
45

@@ -14,6 +15,11 @@ public class IdentityPolicyContext : IIdentityPolicyContext
1415
/// </summary>
1516
public IComponentId PolicyId { get; internal set; }
1617

18+
/// <summary>
19+
/// Returns the policy type.
20+
/// </summary>
21+
public Type Policy { get; internal set; }
22+
1723
/// <summary>
1824
/// Returns the associated plugin context.
1925
/// </summary>

0 commit comments

Comments
 (0)