public async Task GetEntitlement_NotEntitled() { var userUid = Guid.NewGuid(); var customerUid = Guid.NewGuid(); var request = new EntitlementRequestModel { OrganizationIdentifier = customerUid.ToString(), UserUid = userUid.ToString(), UserEmail = "*****@*****.**", Sku = "some sku", Feature = "some feature" }; mockConfigStore.Setup(c => c.GetValueBool(ConfigConstants.ENABLE_ENTITLEMENTS_CONFIG_KEY, false)).Returns(true); mockEmsClient.Setup(e => e.GetEntitlements(userUid, customerUid, request.Sku, request.Feature, It.IsAny <IHeaderDictionary>())).ReturnsAsync(HttpStatusCode.NoContent); mockAuthn.Setup(a => a.GetApplicationBearerToken()).Returns("some token"); var controller = CreateEntitlementsController(userUid.ToString()); var result = await controller.GetEntitlementInternal(request); Assert.NotNull(result); var response = (result as JsonResult)?.Value as EntitlementResponseModel; Assert.NotNull(response); Assert.Equal(request.OrganizationIdentifier, response.OrganizationIdentifier); Assert.Equal(request.UserUid, response.UserUid); Assert.Equal(request.UserEmail, response.UserEmail); Assert.Equal(request.Sku, response.Sku); Assert.Equal(request.Feature, response.Feature); Assert.False(response.IsEntitled); }
public async Task GetEntitlement_AllowedEmail() { var userUid = Guid.NewGuid(); var customerUid = Guid.NewGuid(); var request = new EntitlementRequestModel { OrganizationIdentifier = customerUid.ToString(), UserUid = userUid.ToString(), UserEmail = "*****@*****.**", Sku = "some sku", Feature = "some feature" }; mockConfigStore.Setup(c => c.GetValueString(ConfigConstants.ENTITLEMENTS_ACCEPT_EMAIL_KEY, string.Empty)).Returns("*****@*****.**"); var controller = CreateEntitlementsController(userUid.ToString()); var result = await controller.GetEntitlementInternal(request); Assert.NotNull(result); var response = (result as JsonResult)?.Value as EntitlementResponseModel; Assert.NotNull(response); Assert.Equal(request.OrganizationIdentifier, response.OrganizationIdentifier); Assert.Equal(request.UserUid, response.UserUid); Assert.Equal(request.UserEmail, response.UserEmail); Assert.Equal(request.Sku, response.Sku); Assert.Equal(request.Feature, response.Feature); Assert.True(response.IsEntitled); }
public async Task GetEntitlement_CheckDisabled() { var userUid = Guid.NewGuid(); var customerUid = Guid.NewGuid(); var request = new EntitlementRequestModel { OrganizationIdentifier = customerUid.ToString(), UserUid = userUid.ToString(), UserEmail = "*****@*****.**", Sku = "some sku", Feature = "some feature" }; mockConfigStore.Setup(c => c.GetValueBool(ConfigConstants.ENABLE_ENTITLEMENTS_CONFIG_KEY, false)).Returns(false); var controller = CreateEntitlementsController(userUid.ToString()); var result = await controller.GetEntitlementInternal(request); Assert.NotNull(result); var response = (result as JsonResult)?.Value as EntitlementResponseModel; Assert.NotNull(response); Assert.Equal(request.OrganizationIdentifier, response.OrganizationIdentifier); Assert.Equal(request.UserUid, response.UserUid); Assert.Equal(request.UserEmail, response.UserEmail); Assert.Equal(request.Sku, response.Sku); Assert.Equal(request.Feature, response.Feature); Assert.True(response.IsEntitled); }
public async Task <IActionResult> GetEntitlementInternal([FromBody] EntitlementRequestModel request) { Logger.LogInformation($"Internal Entitlement Request: {JsonConvert.SerializeObject(request)}"); if (request == null) { return(BadRequest()); } var validationResult = request.Validate(User.Identity.Name); if (validationResult.Code == ContractExecutionStatesEnum.ValidationError) { Logger.LogWarning(validationResult.Message); return(BadRequest(validationResult.Message)); } var isEntitled = false; if (!string.IsNullOrEmpty(request.UserEmail)) { if (AcceptedEmails == null) { Logger.LogInformation($"Loading testing entitlement accepted emails"); LoadTestingEmails(); } isEntitled = AcceptedEmails.Contains(request.UserEmail.ToLower()); _logger.LogInformation($"{request.UserEmail} {(isEntitled ? "is an accepted email" : "is not in the allowed list")}"); } if (!isEntitled) { var enableEntitlementCheck = ConfigStore.GetValueBool(ConfigConstants.ENABLE_ENTITLEMENTS_CONFIG_KEY, false); if (enableEntitlementCheck) { var statusCode = await EmsClient.GetEntitlements(Guid.Parse(request.UserUid), Guid.Parse(request.OrganizationIdentifier), request.Sku, request.Feature, CustomHeaders); isEntitled = statusCode == HttpStatusCode.OK; } else { Logger.LogInformation($"Entitlement checking is disabled, allowing the request."); isEntitled = true; } } var response = new EntitlementResponseModel { Feature = request.Feature, Sku = request.Sku, IsEntitled = isEntitled, OrganizationIdentifier = request.OrganizationIdentifier, UserUid = request.UserUid, UserEmail = request.UserEmail }; Logger.LogInformation($"Generated Entitlements Response: {JsonConvert.SerializeObject(response)}"); return(Json(response)); }
public void EntitlementRequestModel_MissingJwtUserUid() { var request = new EntitlementRequestModel(); var result = request.Validate(null); Assert.Equal(ContractExecutionStatesEnum.ValidationError, result.Code); Assert.Equal("JWT uuid is empty.", result.Message); }
public void EntitlementRequestModel_MissingRequiredValues() { var request = new EntitlementRequestModel(); ICollection <ValidationResult> results; var validator = new DataAnnotationsValidator(); Assert.False(validator.TryValidate(request, out results)); Assert.Equal(4, results.Count); }
public void EntitlementRequestModel_DifferentJwtUserUid() { var request = new EntitlementRequestModel { UserUid = Guid.NewGuid().ToString() }; var result = request.Validate(Guid.NewGuid().ToString()); Assert.Equal(ContractExecutionStatesEnum.ValidationError, result.Code); Assert.Equal("Provided uuid does not match JWT.", result.Message); }
/// <summary> /// Attempt to fetch the entitlement response from the entitlement server /// Can return a null response in the event of a bad request / mismatched user email to email attached to bearer token /// </summary> /// <returns>Model indicated if the entitlement is allowed, or not - or null in the event of a bad request</returns> public async Task <EntitlementResponseModel> IsEntitled(EntitlementRequestModel request, IHeaderDictionary customHeaders = null) { if (request == null) { throw new ArgumentException("No request provided", nameof(request)); } // In some cases we want to disable entitlements checking, e.g tests or staging // this key allows that at a global level to be disabled, but calling code still operates the same if (!configurationStore.GetValueBool(ConfigConstants.ENABLE_ENTITLEMENTS_CONFIG_KEY, false)) { log.LogInformation($"Entitlements checking is disabled for request {JsonConvert.SerializeObject(request)}"); return(new EntitlementResponseModel { IsEntitled = true, Feature = request.Feature, Sku = request.Sku, OrganizationIdentifier = request.OrganizationIdentifier, UserUid = request.UserUid, UserEmail = request.UserEmail }); } try { await using var ms = new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(request))); var result = await PostMasterDataItemServiceDiscovery <EntitlementResponseModel>("/entitlement", request.OrganizationIdentifier, request.UserUid, customHeaders, null, ms); if (result == null) { log.LogInformation($"No Entitlement returned from the Entitlement Service, returned a failed entitlement request to the caller."); return(new EntitlementResponseModel { IsEntitled = false, Feature = request.Feature, Sku = request.Sku, OrganizationIdentifier = request.OrganizationIdentifier, UserUid = request.UserUid, UserEmail = request.UserEmail }); } log.LogInformation($"User `{result.UserUid}` for Customer: `{request.OrganizationIdentifier}` {(result.IsEntitled ? "is" : "is not")} entitled to use the `{request.Feature}` feature for the `{request.Sku}` product."); return(result); } catch (HttpRequestException e) { log.LogWarning($"Failed to get entitlement, got exception with message: {e.Message}"); return(null); } }
public IActionResult GetMockEntitlement([FromBody] EntitlementRequestModel request) { Logger.LogInformation($"{nameof(GetMockEntitlement)}: UserUid={request.UserUid}"); var response = new EntitlementResponseModel { Feature = request.Feature, Sku = request.Sku, IsEntitled = true, OrganizationIdentifier = request.OrganizationIdentifier, UserUid = request.UserUid, UserEmail = request.UserEmail }; return(Json(response)); }
public async Task GetEntitlement_DifferentUserUid() { var request = new EntitlementRequestModel { OrganizationIdentifier = Guid.NewGuid().ToString(), UserUid = Guid.NewGuid().ToString(), Sku = "some sku", Feature = "some feature" }; var controller = CreateEntitlementsController(Guid.NewGuid().ToString()); var result = await controller.GetEntitlementInternal(request); Assert.NotNull(result); var response = result as BadRequestObjectResult; Assert.NotNull(response); Assert.Equal(400, response.StatusCode); Assert.Equal("Provided uuid does not match JWT.", response.Value); }
/// <summary> /// Invokes the specified context. /// </summary> public async Task Invoke(HttpContext context) { if (IgnoredPaths.Select(s => context.Request.Path.Value.Contains(s)).Contains(true)) { await _next(context); return; } if (!InternalConnection(context)) { bool isApplicationContext; string applicationName; string userUid; string userEmail; var customerUid = string.Empty; string customerName; // todo temporary to look into user info while we test. log.LogDebug($"{nameof(Invoke)}: TIDAuth context Headers {JsonConvert.SerializeObject(context.Request.Headers, Formatting.None)}"); string authorization = context.Request.Headers["X-Jwt-Assertion"]; log.LogDebug($"{nameof(Invoke)}: TIDAuth authorization {JsonConvert.SerializeObject(authorization)}"); // If no authorization header found, nothing to process further // note keep these result messages vague (but distinct): https://www.gnucitizen.org/blog/username-enumeration-vulnerabilities/ if (string.IsNullOrEmpty(authorization)) { log.LogWarning("No account selected for the request"); await SetResult("No account selected", context); return; } try { var jwtToken = new TPaaSJWT(authorization); isApplicationContext = jwtToken.IsApplicationToken; applicationName = jwtToken.ApplicationName; userEmail = isApplicationContext ? applicationName : jwtToken.EmailAddress; userUid = isApplicationContext ? jwtToken.ApplicationId : jwtToken.UserUid.ToString(); if (isApplicationContext) { // Applications can override the User ID, so we can fetch 'per user' information // E.g Scheduled reports needs to get the Preferences for the user they are running on behalf of, not the Report Server settings. var overrideUserUid = context.Request.Headers[HeaderConstants.X_VISION_LINK_USER_UID]; if (!string.IsNullOrEmpty(overrideUserUid)) { log.LogInformation($"Overriding User ID via {HeaderConstants.X_VISION_LINK_USER_UID} header with {overrideUserUid}, for application request from {applicationName}."); userUid = overrideUserUid; } } } catch (Exception e) { log.LogWarning(e, "Invalid authentication with exception"); await SetResult("Invalid authentication", context); return; } var requireCustomerUid = RequireCustomerUid(context); if (requireCustomerUid) { customerUid = context.Request.Headers["X-VisionLink-CustomerUID"]; } // If required customer not provided, nothing to process further if (string.IsNullOrEmpty(customerUid) && requireCustomerUid) { log.LogWarning("No account found for the request"); await SetResult("No account found", context); return; } var customHeaders = context.Request.Headers.GetCustomHeaders(); //If this is an application context do not validate user-customer if (isApplicationContext) { log.LogInformation( $"Authorization: Calling context is 'Application' for Customer: {customerUid} Application: {userUid} ApplicationName: {applicationName}"); customerName = "Application"; } // User must have be authenticated against this customer else if (requireCustomerUid) { try { // the TID userId is the guid portion of the TRN var customer = await accountClient.GetMyAccount(new Guid(userUid), new Guid(customerUid), customHeaders); if (customer == null) { var error = $"User {userUid} is not authorized to configure this customer {customerUid}"; log.LogWarning(error); await SetResult(error, context); return; } // do we need to check entitlements? If so, this will call out to an another service to check. if (RequireEntitlementValidation(context)) { var entitlementRequest = new EntitlementRequestModel { Feature = EntitlementFeature, Sku = EntitlementSku, OrganizationIdentifier = customerUid, UserUid = userUid, UserEmail = userEmail }; var result = await _entitlementProxy.IsEntitled(entitlementRequest, customHeaders); if (result == null || !result.IsEntitled) { log.LogWarning($"No entitlement for the request"); await SetResult($"User is not entitled to use feature `{EntitlementFeature}` for product `{EntitlementSku}`", context); return; } log.LogInformation($"User is entitled to use feature `{EntitlementFeature}` for product `{EntitlementSku}`"); } customerName = customer.Name; } catch (Exception e) { log.LogWarning( $"Unable to access the 'accountClient.GetMyAccount' Message: {e.Message}."); await SetResult("Failed authentication", context); return; } } else { customerName = "Unknown"; } log.LogInformation($"Authorization: for Customer: {customerUid} userUid: {userUid} userEmail: {userEmail} allowed"); //Set calling context Principal context.User = CreatePrincipal(userUid, customerUid, customerName, userEmail, isApplicationContext, customHeaders, applicationName); } await _next.Invoke(context); }