Skip to content

Commit

Permalink
Prevent users who have prohibitions accessing services (#754)
Browse files Browse the repository at this point in the history
  • Loading branch information
gunndabad authored Nov 3, 2023
1 parent 5b2a6bb commit f2294f6
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,7 @@ public OAuthAuthorizationState(string clientId, string scope, string? redirectUr
public string? RedirectUri { get; }
public TrnRequirementType? TrnRequirementType { get; init; }
public TrnMatchPolicy? TrnMatchPolicy { get; set; }
public bool? BlockProhibitedTeachers { get; set; }

public string ResolveServiceUrl(Application application)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public async Task<IActionResult> Authorize()

TrnRequirementType? trnRequirementType = null;
TrnMatchPolicy? trnMatchPolicy = null;
bool? blockProhibitedTeachers = null;

if (userRequirements.HasFlag(UserRequirements.TrnHolder))
{
Expand Down Expand Up @@ -140,10 +141,31 @@ public async Task<IActionResult> Authorize()
}));
}
}

var requestedBlockProhibitedTeachers = request["block_prohibited_teachers"];
if (requestedBlockProhibitedTeachers.HasValue)
{
if (bool.TryParse(requestedBlockProhibitedTeachers?.Value as string, out var parsedBlockProhibitedTeachers))
{
blockProhibitedTeachers = parsedBlockProhibitedTeachers;
}
else
{
return Forbid(
authenticationSchemes: AuthenticationSchemes.Oidc,
properties: new AuthenticationProperties(new Dictionary<string, string?>()
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidRequest,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
"Invalid block_prohibited_teachers specified."
}));
}
}
}

trnRequirementType ??= client.TrnRequirementType;
trnMatchPolicy ??= client.TrnMatchPolicy;
blockProhibitedTeachers ??= client.BlockProhibitedTeachers;
}

var sessionId = request["session_id"]?.Value as string;
Expand All @@ -157,7 +179,8 @@ public async Task<IActionResult> Authorize()
oAuthState: new OAuthAuthorizationState(request.ClientId!, request.Scope!, request.RedirectUri)
{
TrnRequirementType = trnRequirementType,
TrnMatchPolicy = trnMatchPolicy
TrnMatchPolicy = trnMatchPolicy,
BlockProhibitedTeachers = blockProhibitedTeachers
},
authenticateResult.Succeeded != true);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
@{
ViewBag.Title = Model.TrnVerificationElevationSuccessful == true ? "The information you gave has been verified" :
Model.TrnVerificationElevationSuccessful == false ? "The information you gave could not be verified" :
!Model.CanAccessService ? "You cannot access this service yet" :
!Model.CanAccessService ? $"You cannot {Model.ClientDisplayName} online" :
Model.FirstTimeSignInForEmail ? "You’ve created a DfE Identity account" :
"You’ve signed in to your DfE Identity account";

Expand Down Expand Up @@ -50,7 +50,19 @@
}
else if (Model.TrnRequirementType == TrnRequirementType.Required)
{
if (Model.TrnLookupStatus == TrnLookupStatus.Found)
if (Model.TrnLookupStatus == TrnLookupStatus.Found && !Model.CanAccessService)
{
if (Model.FirstTimeSignInForEmail)
{
<p>Youve created a DfE Identity account but cannot use it for this service.</p>
}

<p>
Email <a href="mailto:@(Configuration["SupportEmail"])">@(Configuration["SupportEmail"])</a>
to find out how to @Model.ClientDisplayName.
</p>
}
else if (Model.TrnLookupStatus == TrnLookupStatus.Found)
{
if (Model.FirstTimeSignInForEmail)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using TeacherIdentity.AuthServer.Journeys;
using TeacherIdentity.AuthServer.Models;
using TeacherIdentity.AuthServer.Oidc;
using TeacherIdentity.AuthServer.Services.DqtApi;
using TeacherIdentity.AuthServer.State;

namespace TeacherIdentity.AuthServer.Pages.SignIn;
Expand All @@ -15,15 +16,18 @@ public class CompleteModel : PageModel
private readonly SignInJourney _journey;
private readonly TeacherIdentityApplicationManager _applicationManager;
private readonly TeacherIdentityServerDbContext _dbContext;
private readonly IDqtApiClient _dqtApiClient;

public CompleteModel(
SignInJourney journey,
TeacherIdentityApplicationManager applicationManager,
TeacherIdentityServerDbContext dbContext)
TeacherIdentityServerDbContext dbContext,
IDqtApiClient dqtApiClient)
{
_journey = journey;
_applicationManager = applicationManager;
_dbContext = dbContext;
_dqtApiClient = dqtApiClient;
}

public string? Email { get; set; }
Expand Down Expand Up @@ -60,22 +64,41 @@ public async Task OnGet()
RedirectUri = authenticationState.OAuthState.RedirectUri;
ResponseMode = authenticationState.OAuthState.AuthorizationResponseMode!;
ResponseParameters = authenticationState.OAuthState.AuthorizationResponseParameters!;
CanAccessService = authenticationState.OAuthState?.TrnRequirementType != Models.TrnRequirementType.Required || authenticationState.Trn is not null;
Email = authenticationState.EmailAddress;
FirstTimeSignInForEmail = authenticationState.FirstTimeSignInForEmail!.Value;
Trn = authenticationState.Trn;
TrnVerificationElevationSuccessful = authenticationState.TrnVerificationElevationSuccessful;
TrnLookupStatus = authenticationState.TrnLookupStatus;
TrnRequirementType = authenticationState.OAuthState?.TrnRequirementType;
TrnMatchPolicy = authenticationState.OAuthState?.TrnMatchPolicy;
TrnRequirementType = authenticationState.OAuthState.TrnRequirementType;
TrnMatchPolicy = authenticationState.OAuthState.TrnMatchPolicy;

var user = await _dbContext.Users.SingleAsync(u => u.UserId == authenticationState.UserId);
TrnLookupSupportTicketCreated = user?.TrnLookupSupportTicketCreated == true;

var clientId = authenticationState.OAuthState?.ClientId;
var clientId = authenticationState.OAuthState.ClientId;
var client = await _applicationManager.FindByClientIdAsync(clientId!);
ClientDisplayName = await _applicationManager.GetDisplayNameAsync(client!);

CanAccessService = authenticationState.OAuthState.TrnRequirementType switch
{
Models.TrnRequirementType.Required => authenticationState.Trn is not null,
_ => true
};

if (authenticationState.OAuthState.TrnRequirementType == Models.TrnRequirementType.Required &&
authenticationState.OAuthState.BlockProhibitedTeachers == true &&
authenticationState.Trn is string trn &&
CanAccessService)
{
var dqtUser = await _dqtApiClient.GetTeacherByTrn(trn) ??
throw new Exception($"Failed to retreive teacher with TRN {trn} from DQT.");

if (dqtUser.Alerts.Any(a => a.AlertType == AlertType.Prohibition))
{
CanAccessService = false;
}
}

HttpContext.Features.Get<WebRequestEventFeature>()?.Event.AddTag(FirstTimeSignInForEmail ? "FirstTimeUser" : "ReturningUser");
}

Expand Down
6 changes: 6 additions & 0 deletions dotnet-authserver/src/TeacherIdentity.TestClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ public static void Main(string[] args)
ctx.ProtocolMessage.SetParameter("trn_match_policy", trnMatchPolicy);
}

var blockProhibitedTeachers = ctx.HttpContext.Request.Query["block_prohibited_teachers"].ToString();
if (!string.IsNullOrEmpty(blockProhibitedTeachers))
{
ctx.ProtocolMessage.SetParameter("block_prohibited_teachers", blockProhibitedTeachers);
}

var trnToken = ctx.HttpContext.Request.Query["trn_token"].ToString();
if (!string.IsNullOrEmpty(trnToken))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</a>
</li>
<li>
<a asp-action="Profile" asp-route-scope="email openid profile dqt:read" asp-route-trn_requirement="Required" asp-route-trn_match_policy="Strict" class="govuk-link">
<a asp-action="Profile" asp-route-scope="email openid profile dqt:read" asp-route-trn_requirement="Required" asp-route-trn_match_policy="Strict" asp-route-block_prohibited_teachers="true" class="govuk-link">
Core + TRN lookup (Access your teaching qualifications)
</a>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public async Task Get_ValidRequest_RendersExpectedContent(
false,
new[]
{
"You cannot access this service yet",
$"You cannot {TestClients.DefaultClient.DisplayName} online",
"This could be because you do not have teaching qualifications, for example, qualified teacher status (QTS).",
"You’ve created a DfE Identity account. When you’re eligible to use this service, you can sign in just using your email"
}
Expand All @@ -250,7 +250,7 @@ public async Task Get_ValidRequest_RendersExpectedContent(
true,
new[]
{
"You cannot access this service yet",
$"You cannot {TestClients.DefaultClient.DisplayName} online",
"We need to do some more checks to see if your details are in our records.",
"We’ll email you when we’ve completed those checks - we may need some more information.",
"You’ve created a DfE Identity account. To sign in to this service in the future, you’ll just need your email address"
Expand Down Expand Up @@ -282,7 +282,7 @@ public async Task Get_ValidRequest_RendersExpectedContent(
false,
new[]
{
"You cannot access this service yet",
$"You cannot {TestClients.DefaultClient.DisplayName} online",
"This could be because you do not have teaching qualifications, for example, qualified teacher status (QTS).",
"You’ve signed in to your DfE Identity account"
}
Expand Down Expand Up @@ -313,7 +313,7 @@ public async Task Get_ValidRequest_RendersExpectedContent(
true,
new[]
{
"You cannot access this service yet",
$"You cannot {TestClients.DefaultClient.DisplayName} online",
"We need to do some more checks to see if your details are in our records.",
"We’ll email you when we’ve completed those checks - we may need some more information.",
"You’ve signed in to your DfE Identity account"
Expand Down

0 comments on commit f2294f6

Please sign in to comment.