Resolve "API tokens" #41
@@ -1,4 +1,5 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationHandler_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fca451c12d69fe026a0e7e9b1a0ddbf4cf6f6b8316cb2aec7984a7241813f648_003FAuthenticationHandler_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationSchemeOptions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F8525b7a9e58c77f532f1a88d4f2897e3c2baf316b9eb2c391b242a3885fcce6_003FAuthenticationSchemeOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAuthenticationSchemeOptions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F8525b7a9e58c77f532f1a88d4f2897e3c2baf316b9eb2c391b242a3885fcce6_003FAuthenticationSchemeOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEditContextDataAnnotationsExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbc307cd57fb42fc4c7fb9795381958122734d3750f41b6c1735c7d132ecda70_003FEditContextDataAnnotationsExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEditContextDataAnnotationsExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbc307cd57fb42fc4c7fb9795381958122734d3750f41b6c1735c7d132ecda70_003FEditContextDataAnnotationsExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbd1d5c50194fea68ff3559c160230b0ab50f5acf4ce3061bffd6d62958e2182_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExceptionDispatchInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fbd1d5c50194fea68ff3559c160230b0ab50f5acf4ce3061bffd6d62958e2182_003FExceptionDispatchInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
@@ -71,6 +72,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</wpf:ResourceDictionary>
|
</wpf:ResourceDictionary>
|
||||||
@@ -23,8 +23,6 @@ by configuring your configuration to load these.
|
|||||||
> `builder.Configuration.AddEnvironmentVariables();` to your startup configuration before you add the
|
> `builder.Configuration.AddEnvironmentVariables();` to your startup configuration before you add the
|
||||||
> custom configurations / HopFrame services.
|
> custom configurations / HopFrame services.
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
You can specify `Seconds`, `Minutes`, `Hours` and `Days` for either of the two token types.
|
You can specify `Seconds`, `Minutes`, `Hours` and `Days` for either of the two token types.
|
||||||
These get combined to a single time span.
|
These get combined to a single time span.
|
||||||
|
|
||||||
@@ -49,3 +47,28 @@ HOPFRAME__AUTHENTICATION__ACCESSTOKEN__MINUTES=30
|
|||||||
HOPFRAME__AUTHENTICATION__REFRESHTOKEN__DAYS=10
|
HOPFRAME__AUTHENTICATION__REFRESHTOKEN__DAYS=10
|
||||||
HOPFRAME__AUTHENTICATION__REFRESHTOKEN__HOURS=5
|
HOPFRAME__AUTHENTICATION__REFRESHTOKEN__HOURS=5
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## API tokens
|
||||||
|
|
||||||
|
API tokens are useful to use in automation environments that need to access an endpoint or page of your application.
|
||||||
|
The HopFrame supports this natively and no further configuration is required in order to use them.
|
||||||
|
|
||||||
|
### Create an api token
|
||||||
|
|
||||||
|
You can create an api token via the `ITokenRepository`:
|
||||||
|
```csharp
|
||||||
|
tokens.CreateApiToken(user, DateTime.MaxValue);
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates a new api token that is valid until the provided DateTime has passed. Note that in the database and the token
|
||||||
|
model the `CreatedAt` property represents the expiration date on an api token. For security reasons the api token by default
|
||||||
|
has no permissions. This allows you to create tokens that are just permitted to perform a single action. Note that a token
|
||||||
|
associated to a user can also have more permissions than the user itself so make sure to properly secure the creation process.
|
||||||
|
|
||||||
|
### Add permissions to an api token
|
||||||
|
|
||||||
|
You can add permissions to an api token like you would to a normal user or group:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
permissions.AddPermission(apiToken, "token.permission");
|
||||||
|
```
|
||||||
|
|||||||
@@ -35,16 +35,18 @@ public class Permission {
|
|||||||
public DateTime GrantedAt { get; set; }
|
public DateTime GrantedAt { get; set; }
|
||||||
public virtual User User { get; set; }
|
public virtual User User { get; set; }
|
||||||
public virtual PermissionGroup Group { get; set; }
|
public virtual PermissionGroup Group { get; set; }
|
||||||
|
public virtual Token Token { get; set; }
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Token
|
## Token
|
||||||
```csharp
|
```csharp
|
||||||
public class Token {
|
public class Token : IPermissionOwner {
|
||||||
public int Type { get; set; }
|
public int Type { get; set; }
|
||||||
public Guid Content { get; set; }
|
public Guid Content { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public virtual User Owner { get; set; }
|
public virtual User Owner { get; set; }
|
||||||
|
public virtual List<Permission> Permissions { get; set; }
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -71,5 +71,9 @@ public interface ITokenRepository {
|
|||||||
Task<Token> CreateToken(int type, User owner);
|
Task<Token> CreateToken(int type, User owner);
|
||||||
|
|
||||||
Task DeleteUserTokens(User owner);
|
Task DeleteUserTokens(User owner);
|
||||||
|
|
||||||
|
Task DeleteToken(Token token);
|
||||||
|
|
||||||
|
Task<Token> CreateApiToken(User owner, DateTime expirationDate);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class AuthenticationTests {
|
|||||||
.ReturnsAsync(correctToken);
|
.ReturnsAsync(correctToken);
|
||||||
|
|
||||||
perms
|
perms
|
||||||
.Setup(x => x.GetFullPermissions(It.IsAny<User>()))
|
.Setup(x => x.GetFullPermissions(It.IsAny<Token>()))
|
||||||
.ReturnsAsync(new List<string>());
|
.ReturnsAsync(new List<string>());
|
||||||
|
|
||||||
var auth = new HopFrameAuthentication(options.Object, logger.Object, encoder.Object, clock.Object, tokens.Object, perms.Object, new OptionsWrapper<HopFrameAuthenticationOptions>(new HopFrameAuthenticationOptions()));
|
var auth = new HopFrameAuthentication(options.Object, logger.Object, encoder.Object, clock.Object, tokens.Object, perms.Object, new OptionsWrapper<HopFrameAuthenticationOptions>(new HopFrameAuthenticationOptions()));
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class AuthMiddlewareTests {
|
|||||||
|
|
||||||
var perms = new Mock<IPermissionRepository>();
|
var perms = new Mock<IPermissionRepository>();
|
||||||
perms
|
perms
|
||||||
.Setup(p => p.GetFullPermissions(It.Is<User>(u => newToken.Owner.Id == u.Id)))
|
.Setup(p => p.GetFullPermissions(It.Is<Token>(u => newToken.Owner.Id == u.Owner.Id)))
|
||||||
.ReturnsAsync(CreateDummyUser().Permissions.Select(p => p.PermissionName).ToList);
|
.ReturnsAsync(CreateDummyUser().Permissions.Select(p => p.PermissionName).ToList);
|
||||||
|
|
||||||
return new AuthMiddleware(auth.Object, perms.Object);
|
return new AuthMiddleware(auth.Object, perms.Object);
|
||||||
|
|||||||
Reference in New Issue
Block a user