Skip to content

Commit f6eeb7b

Browse files
author
gauffininteractive
committed
Fixed so that a user can be removed from an application
1 parent 8ba2574 commit f6eeb7b

File tree

21 files changed

+1357
-908
lines changed

21 files changed

+1357
-908
lines changed

src/Server/OneTrueError.Api/AuthorizeAttribute.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
using System;
2+
using OneTrueError.Api.Core;
23

34
namespace OneTrueError.Api
45
{
56
/// <summary>
67
/// Authorize on specific roles.
78
/// </summary>
8-
[AttributeUsage(AttributeTargets.Class)]
9+
[AttributeUsage(AttributeTargets.Class), IgnoreField]
910
public class AuthorizeRolesAttribute : Attribute
1011
{
1112
/// <summary>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using DotNetCqs;
3+
4+
namespace OneTrueError.Api.Core.Applications.Commands
5+
{
6+
/// <summary>
7+
/// Remove a team member from the
8+
/// </summary>
9+
public class RemoveTeamMember : Command
10+
{
11+
/// <summary>
12+
/// Creates a new instance of <see cref="RemoveTeamMember" />.
13+
/// </summary>
14+
/// <param name="applicationId">Application to remove user from</param>
15+
/// <param name="userToRemove">User id</param>
16+
public RemoveTeamMember(int applicationId, int userToRemove)
17+
{
18+
if (applicationId <= 0) throw new ArgumentOutOfRangeException("applicationId");
19+
if (userToRemove <= 0) throw new ArgumentOutOfRangeException("userToRemove");
20+
ApplicationId = applicationId;
21+
UserToRemove = userToRemove;
22+
}
23+
24+
/// <summary>
25+
/// application to remove user from
26+
/// </summary>
27+
public int ApplicationId { get; private set; }
28+
29+
/// <summary>
30+
/// User id
31+
/// </summary>
32+
public int UserToRemove { get; private set; }
33+
}
34+
}

src/Server/OneTrueError.Api/OneTrueError.Api.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
<Compile Include="Core\Accounts\Events\AccountRegistered.cs" />
6464
<Compile Include="Core\Accounts\Events\InvitationAccepted.cs" />
6565
<Compile Include="Core\Accounts\Events\LoginFailed.cs" />
66+
<Compile Include="Core\Applications\Commands\RemoveTeamMember.cs" />
6667
<Compile Include="Core\Applications\Commands\UpdateApplication.cs" />
6768
<Compile Include="Core\Applications\Events\UserAddedToApplication.cs" />
6869
<Compile Include="Core\Accounts\NamespaceDoc.cs" />
Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,42 @@
1-
using System.Threading.Tasks;
2-
using DotNetCqs;
3-
using Griffin.Container;
4-
using OneTrueError.Api.Core.Applications.Commands;
5-
using OneTrueError.Api.Core.Applications.Events;
6-
7-
namespace OneTrueError.App.Core.Applications.CommandHandlers
8-
{
9-
/// <summary>
10-
/// Handler for <see cref="DeleteApplication" />.
11-
/// </summary>
12-
[Component(RegisterAsSelf = true)]
13-
public class DeleteApplicationHandler : ICommandHandler<DeleteApplication>
14-
{
15-
private readonly IEventBus _eventBus;
16-
private readonly IApplicationRepository _repository;
17-
18-
/// <summary>
19-
/// Creates a new instance of <see cref="DeleteApplicationHandler" />.
20-
/// </summary>
21-
/// <param name="repository">used to delete the application</param>
22-
/// <param name="eventBus">to publish ApplicationDeleted</param>
23-
public DeleteApplicationHandler(IApplicationRepository repository, IEventBus eventBus)
24-
{
25-
_repository = repository;
26-
_eventBus = eventBus;
27-
}
28-
1+
using System.Security.Claims;
2+
using System.Threading.Tasks;
3+
using DotNetCqs;
4+
using Griffin.Container;
5+
using OneTrueError.Api.Core.Applications.Commands;
6+
using OneTrueError.Api.Core.Applications.Events;
7+
using OneTrueError.Infrastructure.Security;
8+
9+
namespace OneTrueError.App.Core.Applications.CommandHandlers
10+
{
11+
/// <summary>
12+
/// Handler for <see cref="DeleteApplication" />.
13+
/// </summary>
14+
[Component(RegisterAsSelf = true)]
15+
public class DeleteApplicationHandler : ICommandHandler<DeleteApplication>
16+
{
17+
private readonly IEventBus _eventBus;
18+
private readonly IApplicationRepository _repository;
19+
20+
/// <summary>
21+
/// Creates a new instance of <see cref="DeleteApplicationHandler" />.
22+
/// </summary>
23+
/// <param name="repository">used to delete the application</param>
24+
/// <param name="eventBus">to publish ApplicationDeleted</param>
25+
public DeleteApplicationHandler(IApplicationRepository repository, IEventBus eventBus)
26+
{
27+
_repository = repository;
28+
_eventBus = eventBus;
29+
}
30+
2931
/// <inheritdoc/>
30-
public async Task ExecuteAsync(DeleteApplication command)
31-
{
32-
var app = await _repository.GetByIdAsync(command.Id);
33-
await _repository.DeleteAsync(command.Id);
34-
var evt = new ApplicationDeleted {ApplicationName = app.Name, ApplicationId = app.Id, AppKey = app.AppKey};
35-
await _eventBus.PublishAsync(evt);
36-
}
37-
}
32+
public async Task ExecuteAsync(DeleteApplication command)
33+
{
34+
ClaimsPrincipal.Current.EnsureApplicationAdmin(command.Id);
35+
36+
var app = await _repository.GetByIdAsync(command.Id);
37+
await _repository.DeleteAsync(command.Id);
38+
var evt = new ApplicationDeleted {ApplicationName = app.Name, ApplicationId = app.Id, AppKey = app.AppKey};
39+
await _eventBus.PublishAsync(evt);
40+
}
41+
}
3842
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Security.Claims;
3+
using System.Threading.Tasks;
4+
using DotNetCqs;
5+
using Griffin.Container;
6+
using log4net;
7+
using OneTrueError.Api.Core.Applications.Commands;
8+
using OneTrueError.Infrastructure.Security;
9+
10+
namespace OneTrueError.App.Core.Applications.CommandHandlers
11+
{
12+
/// <summary>
13+
/// Remove a team member from an application
14+
/// </summary>
15+
[Component]
16+
public class RemoveTeamMemberHandler : ICommandHandler<RemoveTeamMember>
17+
{
18+
private readonly IApplicationRepository _applicationRepository;
19+
private readonly ILog _logger = LogManager.GetLogger(typeof(RemoveTeamMember));
20+
21+
/// <summary>
22+
/// Creates a new instance of <see cref="RemoveTeamMemberHandler" />.
23+
/// </summary>
24+
/// <param name="applicationRepository">To remove member</param>
25+
public RemoveTeamMemberHandler(IApplicationRepository applicationRepository)
26+
{
27+
_applicationRepository = applicationRepository;
28+
}
29+
30+
/// <inheritdoc />
31+
public async Task ExecuteAsync(RemoveTeamMember command)
32+
{
33+
ClaimsPrincipal.Current.EnsureApplicationAdmin(command.ApplicationId);
34+
await _applicationRepository.RemoveTeamMemberAsync(command.ApplicationId, command.UserToRemove);
35+
_logger.Info("Removed " + command.UserToRemove + " from application " + command.ApplicationId);
36+
}
37+
}
38+
}

src/Server/OneTrueError.App/Core/Applications/IApplicationRepository.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,14 @@ public interface IApplicationRepository
7878
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
7979
Task<IList<ApplicationTeamMember>> GetTeamMembersAsync(int applicationId);
8080

81+
/// <summary>
82+
/// remove a member from an application
83+
/// </summary>
84+
/// <param name="applicationId">app</param>
85+
/// <param name="userId">user</param>
86+
/// <returns>task</returns>
87+
Task RemoveTeamMemberAsync(int applicationId, int userId);
88+
8189
/// <summary>
8290
/// Update application member
8391
/// </summary>

src/Server/OneTrueError.App/OneTrueError.App.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@
8585
<Compile Include="Core\ApiKeys\IApiKeyRepository.cs" />
8686
<Compile Include="Core\Applications\ApplicationRole.cs" />
8787
<Compile Include="Core\Applications\CommandHandlers\DeleteApplicationHandler.cs" />
88+
<Compile Include="Core\Applications\CommandHandlers\RemoveTeamMemberHandler.cs" />
8889
<Compile Include="Core\Applications\CommandHandlers\UpdateApplicationHandler.cs" />
8990
<Compile Include="Core\Applications\EventHandlers\UpdateTeamOnInvitationAccepted.cs" />
9091
<Compile Include="Core\Applications\UserApplication.cs" />

src/Server/OneTrueError.Data.Common/Security/ClaimsExtensions.cs

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,20 @@ public static void AddUpdateCredentialClaim(this ClaimsPrincipal principal)
2020
principal.Identities.First().AddClaim(OneTrueClaims.UpdateIdentity);
2121
}
2222

23+
/// <summary>
24+
/// Throws if <see cref="IsApplicationAdmin" /> returns false.
25+
/// </summary>
26+
/// <param name="principal">principal to search in</param>
27+
/// <param name="applicationId">application to check</param>
28+
/// <returns><c>true</c> if the claim was found with the given value; otherwise <c>false</c>.</returns>
29+
/// <exception cref="InvalidOperationException">Claim is not found in the identity.</exception>
30+
public static void EnsureApplicationAdmin(this ClaimsPrincipal principal, int applicationId)
31+
{
32+
if (!IsApplicationAdmin(principal, applicationId))
33+
throw new UnauthorizedAccessException(
34+
$"User {principal.Identity.Name} is not authorized to manage application {applicationId}.");
35+
}
36+
2337
/// <summary>
2438
/// Get account id (<see cref="ClaimTypes.NameIdentifier" />).
2539
/// </summary>
@@ -94,29 +108,33 @@ public static bool IsAccount(this IPrincipal principal, int accountId)
94108
}
95109

96110
/// <summary>
97-
/// Get if the <c>OneTrueClaims.ApplicationAdmin</c> claim is specified for the given application (claim value)
111+
/// Checks if the user has the <c>OneTrueClaims.ApplicationAdmin</c> claim or if user is SysAdmin or System.
98112
/// </summary>
99113
/// <param name="principal">principal to search in</param>
114+
/// <param name="applicationId">Application to check</param>
100115
/// <returns><c>true</c> if the claim was found with the given value; otherwise <c>false</c>.</returns>
101116
/// <exception cref="InvalidOperationException">Claim is not found in the identity.</exception>
102117
public static bool IsApplicationAdmin(this ClaimsPrincipal principal, int applicationId)
103118
{
104-
return
105-
principal.FindFirst(
106-
x => (x.Type == OneTrueClaims.ApplicationAdmin) && (x.Value == applicationId.ToString())) != null;
119+
return principal.HasClaim(OneTrueClaims.ApplicationAdmin, applicationId.ToString())
120+
|| principal.IsInRole(OneTrueClaims.RoleSysAdmin)
121+
|| principal.IsInRole(OneTrueClaims.RoleSystem);
107122
}
108123

109124
/// <summary>
110125
/// Get if the <c>OneTrueClaims.Application</c> claim is specified for the given application (claim value)
111126
/// </summary>
112127
/// <param name="principal">principal to search in</param>
128+
/// <param name="applicationId">App to check</param>
129+
/// <param name="checkSystemRoles">Check if user is in role SysAdmin or if the user is the System.</param>
113130
/// <returns><c>true</c> if the claim was found with the given value; otherwise <c>false</c>.</returns>
114131
/// <exception cref="InvalidOperationException">Claim is not found in the identity.</exception>
115-
public static bool IsApplicationMember(this ClaimsPrincipal principal, int applicationId)
132+
public static bool IsApplicationMember(this ClaimsPrincipal principal, int applicationId, bool checkSystemRoles = false)
116133
{
117-
return
118-
principal.FindFirst(x => (x.Type == OneTrueClaims.Application) && (x.Value == applicationId.ToString())) !=
119-
null;
134+
var isAdmin = principal.HasClaim(OneTrueClaims.Application, applicationId.ToString());
135+
if (checkSystemRoles)
136+
isAdmin = isAdmin || IsSysAdmin(principal) || principal.IsInRole(OneTrueClaims.RoleSystem);
137+
return isAdmin;
120138
}
121139

122140
/// <summary>

src/Server/OneTrueError.SqlServer/Core/Applications/ApplicationRepository.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,5 +174,16 @@ public async Task UpdateAsync(Application entity)
174174
{
175175
await _uow.UpdateAsync(entity);
176176
}
177+
178+
public async Task RemoveTeamMemberAsync(int applicationId, int userId)
179+
{
180+
using (var cmd = (DbCommand)_uow.CreateCommand())
181+
{
182+
cmd.CommandText = "DELETE FROM ApplicationMembers WHERE ApplicationId=@appId AND AccountId = @userId";
183+
cmd.AddParameter("appId", applicationId);
184+
cmd.AddParameter("userId", userId);
185+
await cmd.ExecuteNonQueryAsync();
186+
}
187+
}
177188
}
178189
}

0 commit comments

Comments
 (0)