public void Disables_Ssl_If_SkipSslValidation_Enabled(int skipSslValidation, string syncTriggersUri)
        {
            var vars = new Dictionary <string, string>
            {
                { EnvironmentSettingNames.SkipSslValidation, skipSslValidation.ToString() },
                { EnvironmentSettingNames.AzureWebsiteHostName, "sitename" },
            };

            using (var env = new TestScopedEnvironmentVariable(vars))
            {
                var httpRequest = WebFunctionsManager.BuildSyncTriggersRequest();
                Assert.Equal(syncTriggersUri, httpRequest.RequestUri.AbsoluteUri);
                Assert.Equal(HttpMethod.Post, httpRequest.Method);
            }
        }
        public async Task SetOfflineResponseAsync_ReturnsCorrectResponse()
        {
            string offlineFilePath = null;

            try
            {
                // create a test offline file
                var rootPath = Path.GetTempPath();
                offlineFilePath = TestHelpers.CreateOfflineFile();

                var sendFileFeatureMock = new Mock <IHttpSendFileFeature>();
                sendFileFeatureMock.Setup(s => s.SendFileAsync(offlineFilePath, 0, null, CancellationToken.None)).Returns(Task.FromResult <int>(0));

                // simulate an App Service request
                var vars = new Dictionary <string, string>
                {
                    { EnvironmentSettingNames.AzureWebsiteInstanceId, "123" }
                };
                using (var env = new TestScopedEnvironmentVariable(vars))
                {
                    // without header (thus an internal request)
                    var context = new DefaultHttpContext();
                    context.Features.Set(sendFileFeatureMock.Object);
                    Assert.True(context.Request.IsAppServiceInternalRequest());
                    await context.SetOfflineResponseAsync(rootPath);

                    Assert.Equal(StatusCodes.Status503ServiceUnavailable, context.Response.StatusCode);
                    Assert.Equal(0, context.Response.Body.Length);
                    sendFileFeatureMock.Verify(p => p.SendFileAsync(offlineFilePath, 0, null, CancellationToken.None), Times.Never);

                    // with header (thus an external request)
                    context = new DefaultHttpContext();
                    context.Features.Set(sendFileFeatureMock.Object);
                    context.Request.Headers.Add(ScriptConstants.AntaresLogIdHeaderName, new StringValues("456"));
                    Assert.False(context.Request.IsAppServiceInternalRequest());
                    await context.SetOfflineResponseAsync(rootPath);

                    Assert.Equal(StatusCodes.Status503ServiceUnavailable, context.Response.StatusCode);
                    Assert.Equal("text/html", context.Response.Headers["Content-Type"]);
                    sendFileFeatureMock.Verify(p => p.SendFileAsync(offlineFilePath, 0, null, CancellationToken.None), Times.Once);
                }
            }
            finally
            {
                TestHelpers.DeleteTestFile(offlineFilePath);
            }
        }
Example #3
0
        public async Task TrySyncTriggers_BackgroundSync_DoesNotPostsEmptyContent()
        {
            _emptyContent = true;

            using (var env = new TestScopedEnvironmentVariable(_vars))
            {
                var syncResult = await _functionsSyncManager.TrySyncTriggersAsync(isBackgroundSync : true);

                Assert.Equal(0, _mockHttpHandler.RequestCount);
                Assert.Equal(0, _contentBuilder.Length);
                Assert.True(syncResult.Success);
                Assert.Null(syncResult.Error);

                var logs = _loggerProvider.GetAllLogMessages().Where(m => m.Category.Equals(SyncManagerLogCategory)).Select(p => p.FormattedMessage).ToArray();
                Assert.Equal("No functions found. Skipping Sync operation.", logs.Single());
            }
        }
        public async Task TrySyncTriggers_PostsExpectedContent()
        {
            using (var env = new TestScopedEnvironmentVariable(_vars))
            {
                // Act
                var result = await _functionsSyncManager.TrySyncTriggersAsync();

                var triggers = JArray.Parse(_contentBuilder.ToString());

                // Assert
                Assert.True(result.Success, "SyncTriggers should return success true");
                Assert.True(string.IsNullOrEmpty(result.Error), "Error should be null or empty");

                // verify triggers
                Assert.Equal(_expectedSyncTriggersPayload, triggers.ToString(Formatting.None));
            }
        }
        public void IssuedToken_WithInvalidValues_FailsValidation()
        {
            using (var variables = new TestScopedEnvironmentVariable(Constants.AzureWebsiteLocalEncryptionKey, TestKeyValue))
            {
                var token = JwtGenerator.GenerateToken("testissuer", "testaudience");

                var testParameters = new TokenValidationParameters()
                {
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(TestKeyValue)),
                    ValidateIssuer   = true,
                    ValidateAudience = true
                };

                bool result = JwtGenerator.IsTokenValid(token, testParameters);

                Assert.False(result);
            }
        }
        public void GeneratedToken_ContainsExpectedClaims()
        {
            using (var variables = new TestScopedEnvironmentVariable(Constants.AzureWebsiteLocalEncryptionKey, TestKeyValue))
            {
                var issuer     = "testissuer";
                var audience   = "testaudience";
                var expiration = new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                var notBefore  = expiration.AddSeconds(-10);

                var token = JwtGenerator.GenerateToken(issuer, audience, notBefore, expiration);

                var jwt = new JwtSecurityToken(token);

                Assert.Equal(issuer, jwt.Issuer);
                Assert.Equal(audience, jwt.Audiences.First());
                Assert.Equal(expiration, jwt.ValidTo);
                Assert.Equal(notBefore, jwt.ValidFrom);
            }
        }
Example #7
0
        public async Task TrySyncTriggers_MaxSyncTriggersPayloadSize_Succeeds()
        {
            // create a dummy file that pushes us over size
            string maxString = new string('x', ScriptConstants.MaxTriggersStringLength + 1);

            _function1 = $"{{ bindings: [], test: '{maxString}'}}";

            using (var env = new TestScopedEnvironmentVariable(_vars))
            {
                Assert.True(_functionsSyncManager.ArmCacheEnabled);

                var result = await _functionsSyncManager.TrySyncTriggersAsync();

                Assert.True(result.Success);

                string syncString = _contentBuilder.ToString();
                Assert.True(syncString.Length < ScriptConstants.MaxTriggersStringLength);
                var syncContent = JToken.Parse(syncString);
                Assert.Equal(JTokenType.Array, syncContent.Type);
            }
        }
Example #8
0
        public async Task VerifyDurableTaskHubNameIsAdded()
        {
            var vars = new Dictionary <string, string>
            {
                { EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestHelpers.GenerateKeyHexString() },
                { EnvironmentSettingNames.AzureWebsiteHostName, "appName.azurewebsites.net" }
            };

            using (var env = new TestScopedEnvironmentVariable(vars))
            {
                // Setup
                const string expectedSyncTriggersPayload = "[{\"authLevel\":\"anonymous\",\"type\":\"httpTrigger\",\"direction\":\"in\",\"name\":\"req\",\"functionName\":\"function1\"}," +
                                                           "{\"name\":\"myQueueItem\",\"type\":\"orchestrationTrigger\",\"direction\":\"in\",\"queueName\":\"myqueue-items\",\"connection\":\"DurableStorage\",\"functionName\":\"function2\",\"taskHubName\":\"TestHubValue\"}," +
                                                           "{\"name\":\"myQueueItem\",\"type\":\"activityTrigger\",\"direction\":\"in\",\"queueName\":\"myqueue-items\",\"connection\":\"DurableStorage\",\"functionName\":\"function3\",\"taskHubName\":\"TestHubValue\"}]";
                var options        = CreateApplicationHostOptions();
                var fileSystem     = CreateFileSystem(options.ScriptPath);
                var loggerFactory  = MockNullLogerFactory.CreateLoggerFactory();
                var contentBuilder = new StringBuilder();
                var httpClient     = CreateHttpClient(contentBuilder);
                var factory        = new TestOptionsFactory <ScriptApplicationHostOptions>(options);
                var tokenSource    = new TestChangeTokenSource();
                var changeTokens   = new[] { tokenSource };
                var optionsMonitor = new OptionsMonitor <ScriptApplicationHostOptions>(factory, changeTokens, factory);
                var webManager     = new WebFunctionsManager(optionsMonitor, new OptionsWrapper <LanguageWorkerOptions>(CreateLanguageWorkerConfigSettings()), loggerFactory, httpClient);

                FileUtility.Instance = fileSystem;

                // Act
                (var success, var error) = await webManager.TrySyncTriggers();

                var content = contentBuilder.ToString();

                // Assert
                Assert.True(success, "SyncTriggers should return success true");
                Assert.True(string.IsNullOrEmpty(error), "Error should be null or empty");
                Assert.Equal(expectedSyncTriggersPayload, content);
            }
        }
Example #9
0
        public async Task Legacy_RequestTypes_Succeed()
        {
            var vars = new Dictionary <string, string>
            {
                { LanguageWorkerConstants.FunctionWorkerRuntimeSettingName, LanguageWorkerConstants.DotNetLanguageWorkerName }
            };

            using (var env = new TestScopedEnvironmentVariable(vars))
            {
                string functionKey = await _fixture.Host.GetFunctionSecretAsync("HttpTrigger-Compat");

                string             id      = Guid.NewGuid().ToString();
                string             uri     = $"api/HttpTrigger-Compat?code={functionKey}";
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);

                HttpResponseMessage response = await _fixture.Host.HttpClient.SendAsync(request);

                string responseContent = await response.Content.ReadAsAsync <string>();

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                Assert.Equal("Hello from HttpResponseMessage", responseContent);
            }
        }
Example #10
0
        public async Task VerifyDurableTaskHubNameIsAdded()
        {
            var vars = new Dictionary <string, string>
            {
                { EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestHelpers.GenerateKeyHexString() },
                { EnvironmentSettingNames.AzureWebsiteHostName, "appName.azurewebsites.net" }
            };

            using (var env = new TestScopedEnvironmentVariable(vars))
            {
                // Setup
                const string expectedSyncTriggersPayload = "[{\"authLevel\":\"anonymous\",\"type\":\"httpTrigger\",\"direction\":\"in\",\"name\":\"req\",\"functionName\":\"function1\"}," +
                                                           "{\"name\":\"myQueueItem\",\"type\":\"orchestrationTrigger\",\"direction\":\"in\",\"queueName\":\"myqueue-items\",\"connection\":\"DurableStorage\",\"functionName\":\"function2\",\"taskHubName\":\"TestHubValue\"}," +
                                                           "{\"name\":\"myQueueItem\",\"type\":\"activityTrigger\",\"direction\":\"in\",\"queueName\":\"myqueue-items\",\"connection\":\"DurableStorage\",\"functionName\":\"function3\",\"taskHubName\":\"TestHubValue\"}]";
                var settings             = CreateWebSettings();
                var fileSystem           = CreateFileSystem(settings.ScriptPath);
                var loggerFactory        = MockNullLogerFactory.CreateLoggerFactory();
                var contentBuilder       = new StringBuilder();
                var httpClient           = CreateHttpClient(contentBuilder);
                var proxyMetadataManager = new Mock <IProxyMetadataManager>(MockBehavior.Strict);
                var proxyMetadata        = new ProxyMetadataInfo(new FunctionMetadata[0].ToImmutableArray(), null, null);
                proxyMetadataManager.SetupGet(p => p.ProxyMetadata).Returns(proxyMetadata);
                var webManager = new WebFunctionsManager(new OptionsWrapper <ScriptApplicationHostOptions>(settings), new OptionsWrapper <LanguageWorkerOptions>(CreateLanguageWorkerConfigSettings()), loggerFactory, httpClient, proxyMetadataManager.Object);

                FileUtility.Instance = fileSystem;

                // Act
                (var success, var error) = await webManager.TrySyncTriggers();

                var content = contentBuilder.ToString();

                // Assert
                Assert.True(success, "SyncTriggers should return success true");
                Assert.True(string.IsNullOrEmpty(error), "Error should be null or empty");
                Assert.Equal(expectedSyncTriggersPayload, content);
            }
        }
Example #11
0
        public async Task HttpTrigger_Identities_AnonymousAccessSucceeds()
        {
            var vars = new Dictionary <string, string>
            {
                { LanguageWorkerConstants.FunctionWorkerRuntimeSettingName, LanguageWorkerConstants.DotNetLanguageWorkerName },
                { "WEBSITE_AUTH_ENABLED", "TRUE" }
            };

            using (var env = new TestScopedEnvironmentVariable(vars))
            {
                string             uri     = $"api/httptrigger-identities";
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);

                MockEasyAuth(request, "facebook", "Connor McMahon", "10241897674253170");

                HttpResponseMessage response = await this._fixture.Host.HttpClient.SendAsync(request);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                string responseContent = await response.Content.ReadAsStringAsync();

                string[] identityStrings = StripBookendQuotations(responseContent).Split(';');
                Assert.Equal("Identity: (facebook, Connor McMahon, 10241897674253170)", identityStrings[0]);
            }
        }
Example #12
0
        public async Task HttpTrigger_CustomRoute_ReturnsExpectedResponse()
        {
            var vars = new Dictionary <string, string>
            {
                { LanguageWorkerConstants.FunctionWorkerRuntimeSettingName, LanguageWorkerConstants.DotNetLanguageWorkerName }
            };

            using (var env = new TestScopedEnvironmentVariable(vars))
            {
                string functionName = "HttpTrigger-CustomRoute";
                string functionKey  = await _fixture.Host.GetFunctionSecretAsync(functionName);

                string             uri     = $"api/csharp/products/electronics/123/extra?code={functionKey}";
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);

                HttpResponseMessage response = await _fixture.Host.HttpClient.SendAsync(request);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                string json = await response.Content.ReadAsStringAsync();

                var product = JObject.Parse(json);
                Assert.Equal("electronics", (string)product["category"]);
                Assert.Equal(123, (int?)product["id"]);
                var logs = _fixture.Host.GetScriptHostLogMessages("Function.HttpTrigger-CustomRoute.User");
                Assert.Contains(logs, l => string.Equals(l.FormattedMessage, "Parameters: category=electronics id=123 extra=extra"));
                Assert.True(logs.Any(p => p.FormattedMessage.Contains("ProductInfo: Category=electronics Id=123")));

                // test optional id parameter
                // test optional extra parameter (not in POCO binding contract)
                _fixture.Host.ClearLogMessages();
                uri      = $"api/csharp/products/electronics?code={functionKey}";
                request  = new HttpRequestMessage(HttpMethod.Get, uri);
                response = await _fixture.Host.HttpClient.SendAsync(request);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                json = await response.Content.ReadAsStringAsync();

                product = JObject.Parse(json);
                Assert.Equal("electronics", (string)product["category"]);
                Assert.Null((int?)product["id"]);
                logs = _fixture.Host.GetScriptHostLogMessages("Function.HttpTrigger-CustomRoute.User");
                Assert.Contains(logs, l => string.Equals(l.FormattedMessage, "Parameters: category=electronics id= extra="));

                // test optional category parameter
                _fixture.Host.ClearLogMessages();
                uri      = $"api/csharp/products?code={functionKey}";
                request  = new HttpRequestMessage(HttpMethod.Get, uri);
                response = await _fixture.Host.HttpClient.SendAsync(request);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                json = await response.Content.ReadAsStringAsync();

                product = JObject.Parse(json);
                Assert.Null((string)product["category"]);
                Assert.Null((int?)product["id"]);
                logs = _fixture.Host.GetScriptHostLogMessages("Function.HttpTrigger-CustomRoute.User");
                Assert.Contains(logs, l => string.Equals(l.FormattedMessage, "Parameters: category= id= extra="));

                // test a constraint violation (invalid id)
                uri      = $"api/csharp/products/electronics/1x3?code={functionKey}";
                request  = new HttpRequestMessage(HttpMethod.Get, uri);
                response = await _fixture.Host.HttpClient.SendAsync(request);

                Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

                // test a constraint violation (invalid category)
                uri      = $"api/csharp/products/999/123?code={functionKey}";
                request  = new HttpRequestMessage(HttpMethod.Get, uri);
                response = await _fixture.Host.HttpClient.SendAsync(request);

                Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
            }
        }
Example #13
0
        public async Task TrySyncTriggers_PostsExpectedContent(bool cacheEnabled)
        {
            _mockEnvironment.Setup(p => p.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteArmCacheEnabled)).Returns(cacheEnabled ? "1" : "0");

            using (var env = new TestScopedEnvironmentVariable(_vars))
            {
                Assert.Equal(_functionsSyncManager.ArmCacheEnabled, cacheEnabled);

                // Act
                var syncResult = await _functionsSyncManager.TrySyncTriggersAsync();

                // Assert
                Assert.True(syncResult.Success, "SyncTriggers should return success true");
                Assert.True(string.IsNullOrEmpty(syncResult.Error), "Error should be null or empty");

                // verify expected headers
                Assert.Equal(ScriptConstants.FunctionsUserAgent, _mockHttpHandler.LastRequest.Headers.UserAgent.ToString());
                Assert.True(_mockHttpHandler.LastRequest.Headers.Contains(ScriptConstants.AntaresLogIdHeaderName));

                if (cacheEnabled)
                {
                    // verify triggers
                    var result   = JObject.Parse(_contentBuilder.ToString());
                    var triggers = result["triggers"];
                    Assert.Equal(_expectedSyncTriggersPayload, triggers.ToString(Formatting.None));

                    // verify functions
                    var functions = (JArray)result["functions"];
                    Assert.Equal(3, functions.Count);

                    // verify secrets
                    var secrets     = (JObject)result["secrets"];
                    var hostSecrets = (JObject)secrets["host"];
                    Assert.Equal("aaa", (string)hostSecrets["master"]);
                    var hostFunctionSecrets = (JObject)hostSecrets["function"];
                    Assert.Equal("aaa", (string)hostFunctionSecrets["TestHostFunctionKey1"]);
                    Assert.Equal("bbb", (string)hostFunctionSecrets["TestHostFunctionKey2"]);
                    var systemSecrets = (JObject)hostSecrets["system"];
                    Assert.Equal("aaa", (string)systemSecrets["TestSystemKey1"]);
                    Assert.Equal("bbb", (string)systemSecrets["TestSystemKey2"]);

                    var functionSecrets = (JArray)secrets["function"];
                    Assert.Equal(1, functionSecrets.Count);
                    var function1Secrets = (JObject)functionSecrets[0];
                    Assert.Equal("function1", function1Secrets["name"]);
                    Assert.Equal("aaa", (string)function1Secrets["secrets"]["TestFunctionKey1"]);
                    Assert.Equal("bbb", (string)function1Secrets["secrets"]["TestFunctionKey2"]);

                    var logs        = _loggerProvider.GetAllLogMessages();
                    var log         = logs[0];
                    int startIdx    = log.FormattedMessage.IndexOf("Content=") + 8;
                    int endIdx      = log.FormattedMessage.LastIndexOf(')');
                    var triggersLog = log.FormattedMessage.Substring(startIdx, endIdx - startIdx).Trim();
                    var logObject   = JObject.Parse(triggersLog);

                    Assert.Equal(_expectedSyncTriggersPayload, logObject["triggers"].ToString(Formatting.None));
                    Assert.False(triggersLog.Contains("secrets"));
                }
                else
                {
                    var triggers = JArray.Parse(_contentBuilder.ToString());
                    Assert.Equal(_expectedSyncTriggersPayload, triggers.ToString(Formatting.None));

                    var logs        = _loggerProvider.GetAllLogMessages();
                    var log         = logs[0];
                    int startIdx    = log.FormattedMessage.IndexOf("Content=") + 8;
                    int endIdx      = log.FormattedMessage.LastIndexOf(')');
                    var triggersLog = log.FormattedMessage.Substring(startIdx, endIdx - startIdx).Trim();
                    Assert.Equal(_expectedSyncTriggersPayload, triggersLog);
                }
            }
        }