Skip to content

Commit 6d027fe

Browse files
authored
Merge pull request #1258 from ITfoxtec/test
Test
2 parents 3e4729e + efd429d commit 6d027fe

File tree

71 files changed

+1413
-222
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1413
-222
lines changed

.vscode/launch.json

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Launch FoxIDs",
9+
"type": "coreclr",
10+
"request": "launch",
11+
"preLaunchTask": "build FoxIDs",
12+
"program": "${workspaceFolder}/src/FoxIDs/bin/Debug/net9.0/FoxIDs.dll",
13+
"args": [],
14+
"cwd": "${workspaceFolder}/src/FoxIDs",
15+
"stopAtEntry": false,
16+
"serverReadyAction": {
17+
"action": "openExternally",
18+
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
19+
},
20+
"env": {
21+
"ASPNETCORE_ENVIRONMENT": "Development"
22+
}
23+
},
24+
{
25+
"name": "Launch FoxIDs.Control",
26+
"type": "coreclr",
27+
"request": "launch",
28+
"preLaunchTask": "build FoxIDs.Control",
29+
"program": "${workspaceFolder}/src/FoxIDs.Control/bin/Debug/net9.0/FoxIDs.Control.dll",
30+
"args": [],
31+
"cwd": "${workspaceFolder}/src/FoxIDs.Control",
32+
"stopAtEntry": false,
33+
"serverReadyAction": {
34+
"action": "openExternally",
35+
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
36+
},
37+
"env": {
38+
"ASPNETCORE_ENVIRONMENT": "Development"
39+
}
40+
}
41+
],
42+
"compounds": [
43+
{
44+
"name": "Launch FoxIDs & FoxIDs.Control",
45+
"configurations": [
46+
"Launch FoxIDs",
47+
"Launch FoxIDs.Control"
48+
],
49+
"stopAll": true
50+
}
51+
]
52+
}

.vscode/tasks.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"version": "2.0.0",
3+
"tasks": [
4+
{
5+
"label": "build FoxIDs",
6+
"type": "process",
7+
"command": "dotnet",
8+
"args": [
9+
"build",
10+
"${workspaceFolder}/src/FoxIDs/FoxIDs.csproj",
11+
"/property:GenerateFullPaths=true",
12+
"/consoleloggerparameters:NoSummary"
13+
],
14+
"problemMatcher": "$msCompile"
15+
},
16+
{
17+
"label": "build FoxIDs.Control",
18+
"type": "process",
19+
"command": "dotnet",
20+
"args": [
21+
"build",
22+
"${workspaceFolder}/src/FoxIDs.Control/FoxIDs.Control.csproj",
23+
"/property:GenerateFullPaths=true",
24+
"/consoleloggerparameters:NoSummary"
25+
],
26+
"problemMatcher": "$msCompile"
27+
}
28+
]
29+
}

Kubernetes/k8s-foxids-ingress-deployment.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,15 @@ kind: Ingress
33
metadata:
44
name: foxids-ingress-http
55
annotations:
6+
#Rate Limiting
7+
#nginx.ingress.kubernetes.io/limit-connections: "20"
8+
#nginx.ingress.kubernetes.io/limit-rpm: "300"
9+
#nginx.ingress.kubernetes.io/limit-rps: "10"
10+
#nginx.ingress.kubernetes.io/limit-whitelist: "xxx.xxx.xxx.xxx" # your IP Address
11+
#Buffer
612
nginx.ingress.kubernetes.io/proxy-buffers-number: "4"
713
nginx.ingress.kubernetes.io/proxy-buffer-size: "32k"
14+
#Certificate
815
cert-manager.io/issuer: "letsencrypt-production" #production
916
#cert-manager.io/issuer: "letsencrypt-staging" #staging
1017
spec:

docs/deployment-k8s.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,9 @@ kubectl apply -f xxx.yaml --namespace=test
363363
**Log**
364364
All logs from FoxIDs including errors, trace and events is written to `stdout`. Consider how to handle [application logs](https://kubernetes.io/docs/concepts/cluster-administration/logging/) and collect logs from the containers.
365365

366+
**Rate Limiting**
367+
Configure [limits on connections and transmission rates](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rate-limiting) in `k8s-foxids-ingress-deployment.yaml`.
368+
366369
**MongoDB Operator**
367370
Consider MongoDB Operator if you need multiple instances of MongoDB.
368371

docs/login.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ In this example the user is asked to do two-factor authentication with an authen
6565

6666
![2FA example](images/configure-login-2fa-example.png)
6767

68+
A phone number and email can either be configured as a user identifier or as a claim with the `phone_number` and `email` claim types.
69+
6870
The two-factor authentication type is selected as shown in this table.
6971

7072
<table>

docs/reverse-proxy.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ Optionally both requiring (`secret1`) and sending (`secret2`) in a `X-FoxIDs-Sec
4444
</globalRules>
4545

4646
## Read HTTP headers
47-
The FoxIDs site support reading the client IP address in the following HTTP headers in order of priority:
47+
The FoxIDs site support reading the forwarded client IP address in the following HTTP headers in order of priority:
4848

4949
1. `CF-Connecting-IP`
5050
2. `X-Azure-ClientIP`

docs/users-upload.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# Upload users
1+
# Upload many users
22

33
Provisioning your users in an environment, with or without a password:
44

55
- You can upload the users with there password, if you know the users' passwords.
66
- Otherwise, you can upload the users without a password and the users are then requested to set a password with an email or SMS conformation code. Require the users to have either an email or phone number.
77

8-
The users are bulk uploaded to an environment with 1,000 users at the time and supporting upload of millions of users. You can either user the [FoxIDs Control API](control.md#foxids-control-api) directly or use the [seed tool](#upload-with-seed-tool).
8+
The users are bulk uploaded to an environment with 1,000 users at the time and supporting multiple upload of millions of users. You can either user the [FoxIDs Control API](control.md#foxids-control-api) directly or use the [seed tool](#upload-with-seed-tool).
99

1010
## Upload with seed tool
1111

src/FoxIDs.Control/Controllers/Helpers/TReadCertificateController.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,12 @@ public TReadCertificateController(TelemetryScopedLogger logger, IMapper mapper)
2323
this.mapper = mapper;
2424
}
2525

26-
/// <summary>
27-
/// Read JWK with certificate information.
28-
/// </summary>
29-
/// <param name="certificateAndPassword">Base64 URL encode certificate and optionally password.</param>
30-
/// <returns>User.</returns>
31-
[ProducesResponseType(typeof(Api.JwkWithCertificateInfo), StatusCodes.Status200OK)]
32-
public async Task<ActionResult<Api.JwkWithCertificateInfo>> PostReadCertificate([FromBody] Api.CertificateAndPassword certificateAndPassword)
26+
/// <summary>
27+
/// Read JWK with certificate information from PFX.
28+
/// </summary>
29+
/// <param name="certificateAndPassword">Base64 URL encode certificate and optionally password.</param>
30+
[ProducesResponseType(typeof(Api.JwkWithCertificateInfo), StatusCodes.Status200OK)]
31+
public async Task<ActionResult<Api.JwkWithCertificateInfo>> PostReadCertificate([FromBody] Api.CertificateAndPassword certificateAndPassword)
3332
{
3433
if (!await ModelState.TryValidateObjectAsync(certificateAndPassword)) return BadRequest(ModelState);
3534

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using AutoMapper;
2+
using FoxIDs.Infrastructure;
3+
using Api = FoxIDs.Models.Api;
4+
using Microsoft.AspNetCore.Http;
5+
using Microsoft.AspNetCore.Mvc;
6+
using System.Threading.Tasks;
7+
using ITfoxtec.Identity;
8+
using System.Security.Cryptography.X509Certificates;
9+
using System;
10+
using System.ComponentModel.DataAnnotations;
11+
using FoxIDs.Infrastructure.Security;
12+
13+
namespace FoxIDs.Controllers
14+
{
15+
[TenantScopeAuthorize(Constants.ControlApi.Segment.Basic, Constants.ControlApi.Segment.Party)]
16+
public class TReadCertificateFromPemController : ApiController
17+
{
18+
private readonly IMapper mapper;
19+
20+
public TReadCertificateFromPemController(TelemetryScopedLogger logger, IMapper mapper) : base(logger)
21+
{
22+
this.mapper = mapper;
23+
}
24+
25+
/// <summary>
26+
/// Read JWK with certificate information from PEM certificate (.crt) and private key (.key).
27+
/// </summary>
28+
/// <param name="certificateCrtAndKey">PEM certificate and private key.</param>
29+
[ProducesResponseType(typeof(Api.JwkWithCertificateInfo), StatusCodes.Status200OK)]
30+
public async Task<ActionResult<Api.JwkWithCertificateInfo>> PostReadCertificateFromPem([FromBody] Api.CertificateCrtAndKey certificateCrtAndKey)
31+
{
32+
if (!await ModelState.TryValidateObjectAsync(certificateCrtAndKey)) return BadRequest(ModelState);
33+
34+
try
35+
{
36+
var certificate = X509Certificate2.CreateFromPem(certificateCrtAndKey.CertificatePemCrt, certificateCrtAndKey.CertificatePemKey);
37+
var jwt = await certificate.ToFTJsonWebKeyAsync(includePrivateKey: certificate.HasPrivateKey);
38+
return Ok(mapper.Map<Api.JwkWithCertificateInfo>(jwt));
39+
}
40+
catch (ValidationException)
41+
{
42+
throw;
43+
}
44+
catch (Exception ex)
45+
{
46+
throw new ValidationException("Unable to read PEM certificate and key.", ex);
47+
}
48+
}
49+
}
50+
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using AutoMapper;
2+
using FoxIDs.Infrastructure;
3+
using FoxIDs.Repository;
4+
using FoxIDs.Models;
5+
using Api = FoxIDs.Models.Api;
6+
using Microsoft.AspNetCore.Http;
7+
using Microsoft.AspNetCore.Mvc;
8+
using System.Threading.Tasks;
9+
using System;
10+
using FoxIDs.Logic;
11+
using FoxIDs.Infrastructure.Security;
12+
13+
namespace FoxIDs.Controllers
14+
{
15+
[TenantScopeAuthorize]
16+
public class TTrackSendSmsController : ApiController
17+
{
18+
private readonly TelemetryScopedLogger logger;
19+
private readonly IMapper mapper;
20+
private readonly ITenantDataRepository tenantDataRepository;
21+
private readonly TrackCacheLogic trackCacheLogic;
22+
23+
public TTrackSendSmsController(TelemetryScopedLogger logger, IMapper mapper, ITenantDataRepository tenantDataRepository, TrackCacheLogic trackCacheLogic) : base(logger)
24+
{
25+
this.logger = logger;
26+
this.mapper = mapper;
27+
this.tenantDataRepository = tenantDataRepository;
28+
this.trackCacheLogic = trackCacheLogic;
29+
}
30+
31+
/// <summary>
32+
/// Get environment send SMS settings.
33+
/// </summary>
34+
/// <returns>Send SMS settings.</returns>
35+
[ProducesResponseType(typeof(Api.ResourceItem), StatusCodes.Status200OK)]
36+
[ProducesResponseType(StatusCodes.Status204NoContent)]
37+
[ProducesResponseType(StatusCodes.Status404NotFound)]
38+
public async Task<ActionResult<Api.SendSms>> GetTrackSendSms()
39+
{
40+
try
41+
{
42+
var mTrack = await tenantDataRepository.GetTrackByNameAsync(new Track.IdKey { TenantName = RouteBinding.TenantName, TrackName = RouteBinding.TrackName });
43+
if (mTrack.SendSms == null)
44+
{
45+
return NoContent();
46+
}
47+
return Ok(mapper.Map<Api.SendSms>(mTrack.SendSms));
48+
}
49+
catch (FoxIDsDataException ex)
50+
{
51+
if (ex.StatusCode == DataStatusCode.NotFound)
52+
{
53+
logger.Warning(ex, $"NotFound, Get Track.SendSms by environment name '{RouteBinding.TrackName}'.");
54+
return NotFound("Track.SendSms", RouteBinding.TrackName);
55+
}
56+
throw;
57+
}
58+
}
59+
60+
/// <summary>
61+
/// Update environment send SMS settings.
62+
/// </summary>
63+
/// <param name="sendSms">Send SMS settings.</param>
64+
/// <returns>Send SMS settings.</returns>
65+
[ProducesResponseType(typeof(Api.TrackResourceItem), StatusCodes.Status200OK)]
66+
[ProducesResponseType(StatusCodes.Status404NotFound)]
67+
public async Task<ActionResult<Api.SendSms>> PutTrackSendSms([FromBody] Api.SendSms sendSms)
68+
{
69+
try
70+
{
71+
if (!await ModelState.TryValidateObjectAsync(sendSms)) return BadRequest(ModelState);
72+
73+
var trackIdKey = new Track.IdKey { TenantName = RouteBinding.TenantName, TrackName = RouteBinding.TrackName };
74+
var mTrack = await tenantDataRepository.GetTrackByNameAsync(trackIdKey);
75+
76+
mTrack.SendSms = mapper.Map<SendSms>(sendSms);
77+
await tenantDataRepository.UpdateAsync(mTrack);
78+
79+
await trackCacheLogic.InvalidateTrackCacheAsync(trackIdKey);
80+
81+
return Ok(mapper.Map<Api.SendSms>(mTrack.SendSms));
82+
}
83+
catch (FoxIDsDataException ex)
84+
{
85+
if (ex.StatusCode == DataStatusCode.NotFound)
86+
{
87+
logger.Warning(ex, $"NotFound, Update Track.SendSms by environment name '{RouteBinding.TrackName}'.");
88+
return NotFound("Track.SendSms", Convert.ToString(RouteBinding.TrackName));
89+
}
90+
throw;
91+
}
92+
}
93+
94+
/// <summary>
95+
/// Delete environment send SMS settings.
96+
/// </summary>
97+
[ProducesResponseType(StatusCodes.Status204NoContent)]
98+
[ProducesResponseType(StatusCodes.Status404NotFound)]
99+
public async Task<IActionResult> DeleteTrackSendSms()
100+
{
101+
try
102+
{
103+
var trackIdKey = new Track.IdKey { TenantName = RouteBinding.TenantName, TrackName = RouteBinding.TrackName };
104+
var mTrack = await tenantDataRepository.GetTrackByNameAsync(trackIdKey);
105+
106+
mTrack.SendSms = null;
107+
await tenantDataRepository.UpdateAsync(mTrack);
108+
109+
await trackCacheLogic.InvalidateTrackCacheAsync(trackIdKey);
110+
111+
return NoContent();
112+
}
113+
catch (FoxIDsDataException ex)
114+
{
115+
if (ex.StatusCode == DataStatusCode.NotFound)
116+
{
117+
logger.Warning(ex, $"NotFound, Delete Track.SendSms by environment name '{RouteBinding.TrackName}'.");
118+
return NotFound("Track.SendSms", Convert.ToString(RouteBinding.TrackName));
119+
}
120+
throw;
121+
}
122+
}
123+
}
124+
}

0 commit comments

Comments
 (0)