Exemple #1
0
        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);
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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);
        }
Exemple #4
0
        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));
        }
Exemple #5
0
        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);
        }
Exemple #6
0
        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);
        }
Exemple #7
0
        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);
        }
Exemple #8
0
        /// <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);
            }
        }
Exemple #9
0
        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));
        }
Exemple #10
0
        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);
        }
Exemple #11
0
        /// <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);
        }