Skip to content

Commit

Permalink
Adds support for disabling and expiring authorization rules
Browse files Browse the repository at this point in the history
  • Loading branch information
ryannewington committed Nov 7, 2020
1 parent 992f639 commit a655b5a
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
using MahApps.Metro.Controls.Dialogs;
using MahApps.Metro.SimpleChildWindow;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using PropertyChanged;
using Stylet;

namespace Lithnet.AccessManager.Server.UI
Expand Down Expand Up @@ -89,6 +91,38 @@ public AuthorizationMode AuthorizationMode
}
}

[DependsOn(nameof(Expiry), nameof(ExpireRule), nameof(IsDisabled))]
public string Status
{
get
{
return this.IsDisabled ? "Disabled" : this.HasExpired ? "Expired" : "Active";
}
}

public bool IsDisabled
{
get => this.Model.Disabled;
set => this.Model.Disabled = value;
}

public DateTime? Expiry
{
get => this.Model.Expiry?.ToLocalTime();
set => this.Model.Expiry = value?.ToUniversalTime();
}

public bool ExpireRule
{
get => this.Expiry != null;
set => this.Expiry = value ? this.Expiry == null ? DateTime.Now.AddDays(30) : this.Expiry : null;
}

public bool HasExpired
{
get => this.Model.HasExpired();
}

public bool IsModePermission { get => this.AuthorizationMode == AuthorizationMode.SecurityDescriptor; set => this.AuthorizationMode = value ? AuthorizationMode.SecurityDescriptor : AuthorizationMode.PowershellScript; }

public bool IsModeScript { get => this.AuthorizationMode == AuthorizationMode.PowershellScript; set => this.AuthorizationMode = value ? AuthorizationMode.PowershellScript : AuthorizationMode.SecurityDescriptor; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
</StackPanel>-->

<Label Style="{DynamicResource SubDescriptionHeaderStyle}"
Content="Target"
Content="Rule settings"
Margin="0 5 0 0" />
<Separator Margin="5 0 0 10"
Height="1"
Expand All @@ -40,12 +40,15 @@
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="500" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Label Grid.Row="0"
Expand All @@ -72,6 +75,31 @@
Grid.Column="1"
Text="{Binding Description}"
Margin="2" />

<CheckBox Grid.Row="2"
Grid.Column="1"
Content="Disable rule"
Margin="2 5 5 5"
IsChecked="{Binding IsDisabled}" />

<StackPanel Grid.Row="3"
Grid.Column="1"
Orientation="Horizontal">
<CheckBox Content="Expire rule"
Margin="2 5 5 5"
IsChecked="{Binding ExpireRule}" />

<mah:DateTimePicker Margin="5"
SecondsItemStringFormat="D2"
MinutesItemStringFormat="D2"
MinWidth="300"
IsEnabled="{Binding ExpireRule}"
SelectedDateTime="{Binding Expiry}"
SelectedTimeFormat="Short"
SelectedDateFormat="Long" />

</StackPanel>

</Grid>

<Label Style="{DynamicResource SubDescriptionHeaderStyle}"
Expand Down Expand Up @@ -155,26 +183,18 @@
Background="Transparent"
IsEnabled="{Binding IsScriptPermissionAllowed, Mode=OneWay}"
Visibility="{Binding IsScriptVisible, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}"
Margin="2 2 5 2">

<local:EnterpriseEditionBadge Grid.Row="2"
Grid.Column="1"
VerticalAlignment="Top"
Visibility="{Binding ShowPowerShellEnterpriseEditionBadge, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}"
ToolTipText="PowerShell-based authorization is an enterprise edition feature. Click to learn more"
Text="Use a PowerShell script"
Margin="0 0 0 0" />
</RadioButton>
Margin="2 2 5 2"
Content="Use a PowerShell script" />

</StackPanel>

<!--<local:EnterpriseEditionBadge Grid.Row="2"
<local:EnterpriseEditionBadge Grid.Row="2"
Grid.Column="1"
VerticalAlignment="Top"
Visibility="{Binding ShowPowerShellEnterpriseEditionBadge, Converter={StaticResource BooleanToVisibilityConverter}, Mode=OneWay}"
ToolTipText="PowerShell-based authorization is an enterprise edition feature. Click to learn more"
ShowText="False"
Margin="2 0 5 0" />-->
Margin="2 0 5 0" />

<ContentControl Grid.Row="2"
Grid.Column="2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
<GridView>
<GridViewColumn Header="Target" DisplayMemberBinding="{Binding DisplayName}" Width="Auto"/>
<GridViewColumn Header="Type" DisplayMemberBinding="{Binding Type}" Width="Auto"/>
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding Status}" Width="Auto"/>
<GridViewColumn Header="Description" DisplayMemberBinding="{Binding Description}" Width="Auto"/>
</GridView>
</ListView.View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,15 @@ namespace Lithnet.AccessManager.Server.Authorization
{
public class AuthorizationInformationBuilder : IAuthorizationInformationBuilder
{
private readonly IDirectory directory;

private readonly ILogger logger;

private readonly AuthorizationOptions options;

private readonly IPowerShellSecurityDescriptorGenerator powershell;

private readonly IAuthorizationInformationMemoryCache authzCache;

private readonly IComputerTargetProvider computerTargetProvider;

private readonly IAuthorizationContextProvider authorizationContextProvider;

public AuthorizationInformationBuilder(IOptionsSnapshot<AuthorizationOptions> options, IDirectory directory, ILogger<AuthorizationInformationBuilder> logger, IPowerShellSecurityDescriptorGenerator powershell, IAuthorizationInformationMemoryCache authzCache, IComputerTargetProvider computerTargetProvider, IAuthorizationContextProvider authorizationContextProvider)
public AuthorizationInformationBuilder(IOptionsSnapshot<AuthorizationOptions> options, ILogger<AuthorizationInformationBuilder> logger, IPowerShellSecurityDescriptorGenerator powershell, IAuthorizationInformationMemoryCache authzCache, IComputerTargetProvider computerTargetProvider, IAuthorizationContextProvider authorizationContextProvider)
{
this.directory = directory;
this.logger = logger;
this.options = options.Value;
this.powershell = powershell;
Expand Down Expand Up @@ -91,6 +83,11 @@ public AuthorizationInformation BuildAuthorizationInformation(IUser user, ICompu
{
CommonSecurityDescriptor sd;

if (target.IsInactive())
{
continue;
}

if (target.AuthorizationMode == AuthorizationMode.PowershellScript)
{
sd = this.powershell.GenerateSecurityDescriptor(user, computer, target.Script, 30);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public IList<SecurityDescriptorTarget> GetMatchingTargetsForComputer(IComputer c

try
{
if (target.IsInactive())
{
continue;
}

if (target.Type == TargetType.Container)
{
if (computerParents.Value.Any(t => t == targetData.ContainerGuid))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using Lithnet.AccessManager.Server.Configuration;
using Microsoft.Extensions.Logging;
Expand Down Expand Up @@ -61,7 +62,9 @@ public AuthorizationResponse GetAuthorizationResponse(IUser user, IComputer comp
throw new AccessManagerException($"An invalid access mask combination was requested: {requestedAccess}");
}

if (successTargets.Count == 0 || !(info.EffectiveAccess.HasFlag(requestedAccess)))
var matchedTarget = successTargets?.FirstOrDefault(t => t.IsActive());

if (!info.EffectiveAccess.HasFlag(requestedAccess) || matchedTarget == null)
{
this.logger.LogTrace($"User {user.MsDsPrincipalName} is denied {requestedAccess} access for computer {computer.MsDsPrincipalName}");

Expand All @@ -72,9 +75,7 @@ public AuthorizationResponse GetAuthorizationResponse(IUser user, IComputer comp
}
else
{
var matchedTarget = successTargets[0];
this.logger.LogTrace($"User {user.MsDsPrincipalName} is authorized for {requestedAccess} access to computer {computer.MsDsPrincipalName} from target {matchedTarget.Id}");

return BuildAuthZResponseSuccess(requestedAccess, matchedTarget, computer);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public class SecurityDescriptorTarget
{
public string Id { get; set; } = Guid.NewGuid().ToString();

public bool Disabled { get; set; }

public DateTime? Expiry { get; set; }

public string Target { get; set; }

public string Description { get; set; }
Expand All @@ -30,6 +34,21 @@ public class SecurityDescriptorTarget

public AuditNotificationChannels Notifications { get; set; } = new AuditNotificationChannels();

public bool IsActive()
{
return !this.IsInactive();
}

public bool IsInactive()
{
return this.Disabled || this.HasExpired();
}

public bool HasExpired()
{
return this.Expiry != null && DateTime.UtcNow > this.Expiry.Value.ToUniversalTime();
}

public override string ToString()
{
return this.Id;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"Metadata": {
"Usn": 86,
"Usn": 95,
"SchemaVersion": "1.0"
},
"Licensing": {
Expand Down Expand Up @@ -272,6 +272,7 @@
"ComputerTargets": [
{
"Id": "9dc37cc2-45fc-4c53-a397-aa4e84012211",
"Disabled": false,
"Target": "OU=LAPS Testing,DC=EXTDEV1,DC=LOCAL",
"Description": "Grant ryan access to LAPS testing computer in extdev1",
"Type": "Container",
Expand All @@ -295,32 +296,39 @@
}
},
{
"Id": "3708693c-29d7-4efd-bfd8-17d1512f609f",
"Target": "DC=SUBDEV1,DC=IDMDEV1,DC=LOCAL",
"Description": "Grant ryan access to all machines in subdev1",
"Id": "d6e4a8a1-a82d-40f0-b3b9-0c1b986e262a",
"Disabled": false,
"Target": "DC=idmdev1,dc=local",
"Description": "Grant domain admins access to all computers in idmdev1",
"Type": "Container",
"AuthorizationMode": "SecurityDescriptor",
"SecurityDescriptor": "O:SYD:AR(A;;0xe00;;;S-1-5-21-639624971-2667923174-1539603190-1122)",
"SecurityDescriptor": "O:SYD:AR(A;;0xe00;;;BA)(A;;0xe00;;;S-1-5-21-639624971-2667923174-1539603190-1122)",
"Jit": {
"AuthorizingGroup": "SUBDEV1\\G-JIT-%ComputerName%",
"ExpireAfter": "01:30:00"
"AuthorizingGroup": "IDMDEV1\\JIT-%computerName%",
"ExpireAfter": "01:00:00"
},
"Laps": {
"ExpireAfter": "01:30:00",
"ExpireAfter": "01:00:00",
"RetrievalLocation": "Auto"
},
"Notifications": {
"OnFailure": [],
"OnSuccess": []
"OnFailure": [
"email-domain-admins",
"127676fa-695c-40ef-a43c-a53aa5d023c4"
],
"OnSuccess": [
"email-domain-admins",
"127676fa-695c-40ef-a43c-a53aa5d023c4"
]
}
},
{
"Id": "0eb4fc0f-17f5-4603-b732-7b9b5c19ccaf",
"Target": "S-1-5-21-639624971-2667923174-1539603190-3376",
"Description": "Deny ryan access to laps and jit on pc2",
"Id": "5c1c4850-2986-4fba-a171-22c3b581d1c7",
"Disabled": true,
"Target": "S-1-5-21-639624971-2667923174-1539603190-1445",
"Type": "Computer",
"AuthorizationMode": "SecurityDescriptor",
"SecurityDescriptor": "O:SYD:AR(D;;0xe00;;;S-1-5-21-639624971-2667923174-1539603190-1122)",
"SecurityDescriptor": "O:SYD:AR(A;;0x600;;;S-1-5-21-639624971-2667923174-1539603190-3360)(A;;0x1600;;;S-1-5-21-639624971-2667923174-1539603190-43715)",
"Jit": {
"ExpireAfter": "00:00:00"
},
Expand All @@ -334,42 +342,41 @@
}
},
{
"Id": "d6e4a8a1-a82d-40f0-b3b9-0c1b986e262a",
"Target": "DC=idmdev1,dc=local",
"Description": "Grant domain admins access to all computers in idmdev1",
"Type": "Container",
"Id": "0eb4fc0f-17f5-4603-b732-7b9b5c19ccaf",
"Disabled": false,
"Expiry": "2020-11-07T02:48:00Z",
"Target": "S-1-5-21-639624971-2667923174-1539603190-3376",
"Description": "Deny ryan access to laps and jit on pc2",
"Type": "Computer",
"AuthorizationMode": "SecurityDescriptor",
"SecurityDescriptor": "O:SYD:AR(A;;0xe00;;;BA)(A;;0xe00;;;S-1-5-21-639624971-2667923174-1539603190-1122)",
"SecurityDescriptor": "O:SYD:AR(D;;0xe00;;;S-1-5-21-639624971-2667923174-1539603190-1122)",
"Jit": {
"AuthorizingGroup": "IDMDEV1\\JIT-%computerName%",
"ExpireAfter": "01:00:00"
"ExpireAfter": "00:00:00"
},
"Laps": {
"ExpireAfter": "01:00:00",
"ExpireAfter": "00:00:00",
"RetrievalLocation": "Auto"
},
"Notifications": {
"OnFailure": [
"email-domain-admins",
"127676fa-695c-40ef-a43c-a53aa5d023c4"
],
"OnSuccess": [
"email-domain-admins",
"127676fa-695c-40ef-a43c-a53aa5d023c4"
]
"OnFailure": [],
"OnSuccess": []
}
},
{
"Id": "5c1c4850-2986-4fba-a171-22c3b581d1c7",
"Target": "S-1-5-21-639624971-2667923174-1539603190-1445",
"Type": "Computer",
"Id": "3708693c-29d7-4efd-bfd8-17d1512f609f",
"Disabled": false,
"Expiry": "2020-11-07T04:49:00Z",
"Target": "DC=SUBDEV1,DC=IDMDEV1,DC=LOCAL",
"Description": "Grant ryan access to all machines in subdev1",
"Type": "Container",
"AuthorizationMode": "SecurityDescriptor",
"SecurityDescriptor": "O:SYD:AR(A;;0x600;;;S-1-5-21-639624971-2667923174-1539603190-3360)(A;;0x1600;;;S-1-5-21-639624971-2667923174-1539603190-43715)",
"SecurityDescriptor": "O:SYD:AR(A;;0xe00;;;S-1-5-21-639624971-2667923174-1539603190-1122)",
"Jit": {
"ExpireAfter": "00:00:00"
"AuthorizingGroup": "SUBDEV1\\G-JIT-%ComputerName%",
"ExpireAfter": "01:30:00"
},
"Laps": {
"ExpireAfter": "00:00:00",
"ExpireAfter": "01:30:00",
"RetrievalLocation": "Auto"
},
"Notifications": {
Expand Down

0 comments on commit a655b5a

Please sign in to comment.