/// <summary> /// Handle authentication (via Merchant ID) and authorization (via API key). /// MerchantId is delivered as a header since it will (probably) be necessary for /// every call and should not pollute all request-specific models. /// /// Improvement Idea: Allow granular error messages to return to the caller, /// though this can in some instances be a slight security risk. /// Also: Introduce caching for enhanced performance and scalability. /// </summary> /// <param name="merchant">The Merchant based on the Merchant ID that was read from the headers</param> /// <returns></returns> private bool EnsureMerchantValidity(out Merchant merchant) { merchant = null; // check merchant ID if (!Request.Headers.ContainsKey(PaymentGatewayConstants.MerchantHeaderName)) { return(false); } var rawMerchantId = Request.Headers[PaymentGatewayConstants.MerchantHeaderName].First(); if (!Guid.TryParse(rawMerchantId, out var parsedMerchantId)) { return(false); } // check if merchant with the merchant ID exists and is enabled merchant = _merchantRepository.GetByMerchantId(parsedMerchantId); if (merchant == null) { return(false); } if (!merchant.IsEnabled) { return(false); } // check api key if (!Request.Headers.ContainsKey(PaymentGatewayConstants.ApiKeyHeaderName)) { return(false); } var rawApiKey = Request.Headers[PaymentGatewayConstants.ApiKeyHeaderName].First(); var apiKey = Encoding.UTF8.GetString(Convert.FromBase64String(rawApiKey)); if (apiKey != merchant.ApiKey) { return(false); } return(true); }