public async Task ValidateUnderlyingAuthenticatorErrorTest()
        {
            // Arrange
            string iothubHostName          = "testiothub.azure-devices.net";
            string edgehubHostName         = "edgehub1";
            string deviceId                = "d1";
            var    underlyingAuthenticator = Mock.Of <IAuthenticator>();

            Mock.Get(underlyingAuthenticator).Setup(u => u.AuthenticateAsync(It.IsAny <IClientCredentials>())).ThrowsAsync(new TimeoutException());
            var deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();

            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(It.Is <string>(i => i == deviceId)))
            .ReturnsAsync(Option.None <ServiceIdentity>());

            IAuthenticator authenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache.Object, iothubHostName, edgehubHostName, underlyingAuthenticator, true, true);

            var    identity         = Mock.Of <IDeviceIdentity>(d => d.DeviceId == deviceId && d.Id == deviceId);
            string token            = GetDeviceToken(iothubHostName, deviceId, GetKey());
            var    tokenCredentials = Mock.Of <ITokenCredentials>(t => t.Identity == identity && t.Token == token);

            // Act
            await Assert.ThrowsAsync <TimeoutException>(() => authenticator.AuthenticateAsync(tokenCredentials));

            // Assert
            Mock.Get(underlyingAuthenticator).VerifyAll();
            Mock.Get(underlyingAuthenticator).Verify(u => u.AuthenticateAsync(It.IsAny <IClientCredentials>()), Times.Once);
        }
        public async Task AuthenticateTest_DeviceUpdateServiceIdentity()
        {
            // Arrange
            string iothubHostName             = "testiothub.azure-devices.net";
            string edgehubHostName            = "edgehub1";
            string deviceId                   = "d1";
            var    underlyingAuthenticator    = Mock.Of <IAuthenticator>();
            var    deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();
            string key = GetKey();
            var    serviceIdentity1 = new ServiceIdentity(deviceId, "1234", new string[0], new ServiceAuthentication(new SymmetricKeyAuthentication(GetKey(), GetKey())), ServiceIdentityStatus.Enabled);
            var    serviceIdentity2 = new ServiceIdentity(deviceId, "1234", new string[0], new ServiceAuthentication(new SymmetricKeyAuthentication(key, GetKey())), ServiceIdentityStatus.Enabled);

            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(It.Is <string>(i => i == deviceId)))
            .ReturnsAsync(Option.Some(serviceIdentity1));
            deviceScopeIdentitiesCache.Setup(d => d.RefreshServiceIdentity(deviceId))
            .Callback <string>((id) => deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(deviceId)).ReturnsAsync(Option.Some(serviceIdentity2)))
            .Returns(Task.CompletedTask);
            deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == deviceId)))
            .ReturnsAsync(Option.Some(deviceId));

            IAuthenticator authenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache.Object, iothubHostName, edgehubHostName, underlyingAuthenticator, true, true);

            var    identity         = Mock.Of <IDeviceIdentity>(d => d.DeviceId == deviceId && d.Id == deviceId);
            string token            = GetDeviceToken(iothubHostName, deviceId, key);
            var    tokenCredentials = Mock.Of <ITokenCredentials>(t => t.Identity == identity && t.Token == token);

            // Act
            bool isAuthenticated = await authenticator.AuthenticateAsync(tokenCredentials);

            // Assert
            Assert.True(isAuthenticated);
            Mock.Get(underlyingAuthenticator).VerifyAll();
            deviceScopeIdentitiesCache.Verify(d => d.GetServiceIdentity(deviceId), Times.Exactly(2));
            deviceScopeIdentitiesCache.Verify(d => d.RefreshServiceIdentity(deviceId), Times.Once);
        }
        public async Task InvalidAuthChainTest_UnauthorizedActor()
        {
            // Arrange
            string iothubHostName             = "testiothub.azure-devices.net";
            string edgehubHostName            = "edgehub1";
            string rootEdgeId                 = "rootEdge";
            string actorEdgeId                = "childEdge";
            string leafDeviceId               = "leaf";
            var    authChain                  = Option.Some <string>(leafDeviceId + ";" + "NotActorEdge" + ";" + rootEdgeId);
            var    underlyingAuthenticator    = Mock.Of <IAuthenticator>();
            var    deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();
            string key = GetKey();

            deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == leafDeviceId)))
            .ReturnsAsync(authChain);

            var authenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache.Object, iothubHostName, edgehubHostName, underlyingAuthenticator, true, true);

            var    identity         = Mock.Of <IModuleIdentity>(d => d.DeviceId == actorEdgeId && d.ModuleId == Constants.EdgeHubModuleId && d.Id == $"{actorEdgeId}/{Constants.EdgeHubModuleId}");
            string token            = GetDeviceToken(iothubHostName, actorEdgeId, Constants.EdgeHubModuleId, key);
            var    tokenCredentials = Mock.Of <ITokenCredentials>(t => t.Identity == identity && t.Token == token);

            // Act
            bool isAuthenticated = await authenticator.AuthenticateAsync(tokenCredentials);

            // Assert
            Assert.False(isAuthenticated);
        }
        public async Task AuthenticateTest_Nested_Module()
        {
            // Arrange
            string iothubHostName             = "testiothub.azure-devices.net";
            string edgehubHostName            = "edgehub1";
            string actorEdgeId                = "parentEdge";
            string nestedEdgeId               = "childEdge";
            string nestedModuleId             = nestedEdgeId + "/" + Constants.EdgeHubModuleId;
            var    authChain                  = Option.Some <string>(nestedModuleId + ";" + nestedEdgeId + ";" + actorEdgeId);
            var    underlyingAuthenticator    = Mock.Of <IAuthenticator>();
            var    deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();
            string key = GetKey();
            var    nestedModuleIdentity        = Mock.Of <IModuleIdentity>(i => i.DeviceId == nestedEdgeId && i.ModuleId == Constants.EdgeHubModuleId && i.Id == nestedModuleId);
            var    actorAuth                   = new SymmetricKeyAuthentication(key, key);
            var    actorEdgeHubServiceIdentity = new ServiceIdentity(actorEdgeId, Constants.EdgeHubModuleId, null, new List <string>(), "1234", Enumerable.Empty <string>(), new ServiceAuthentication(actorAuth), ServiceIdentityStatus.Enabled);
            string actorEdgeHubId              = actorEdgeHubServiceIdentity.Id;

            deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == nestedModuleId)))
            .ReturnsAsync(authChain);
            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(It.Is <string>(i => i == actorEdgeHubId)))
            .ReturnsAsync(Option.Some(actorEdgeHubServiceIdentity));

            var authenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache.Object, iothubHostName, edgehubHostName, underlyingAuthenticator, true, true, true);

            var    actorEdgeHubIdentity = Mock.Of <IModuleIdentity>(d => d.DeviceId == actorEdgeId && d.ModuleId == Constants.EdgeHubModuleId && d.Id == $"{actorEdgeId}/{Constants.EdgeHubModuleId}");
            string token            = GetDeviceToken(iothubHostName, actorEdgeId, Constants.EdgeHubModuleId, key);
            var    tokenCredentials = Mock.Of <ITokenCredentials>(t => t.Identity == actorEdgeHubIdentity && t.Token == token && t.AuthChain == authChain);

            // Act
            bool isAuthenticated = await authenticator.AuthenticateAsync(tokenCredentials);

            // Assert
            Assert.True(isAuthenticated);
            Mock.Get(underlyingAuthenticator).VerifyAll();
        }
        public async Task AuthenticateTest_Device_TokenExpired()
        {
            // Arrange
            string iothubHostName             = "testiothub.azure-devices.net";
            string edgehubHostName            = "edgehub1";
            string deviceId                   = "d1";
            var    underlyingAuthenticator    = Mock.Of <IAuthenticator>();
            var    deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();
            string key             = GetKey();
            var    serviceIdentity = new ServiceIdentity(deviceId, "1234", new string[0], new ServiceAuthentication(new SymmetricKeyAuthentication(key, GetKey())), ServiceIdentityStatus.Enabled);

            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(It.Is <string>(i => i == deviceId)))
            .ReturnsAsync(Option.Some(serviceIdentity));

            IAuthenticator authenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache.Object, iothubHostName, edgehubHostName, underlyingAuthenticator, true, true);

            var    identity         = Mock.Of <IDeviceIdentity>(d => d.DeviceId == deviceId && d.Id == deviceId);
            string token            = GetDeviceToken(iothubHostName, deviceId, key, TimeSpan.FromHours(-1));
            var    tokenCredentials = Mock.Of <ITokenCredentials>(t => t.Identity == identity && t.Token == token);

            // Act
            bool isAuthenticated = await authenticator.AuthenticateAsync(tokenCredentials);

            // Assert
            Assert.False(isAuthenticated);
            Mock.Get(underlyingAuthenticator).VerifyAll();
        }
        public async Task AuthenticateTest_ModuleWithDeviceKey()
        {
            // Arrange
            string iothubHostName             = "testiothub.azure-devices.net";
            string edgehubHostName            = "edgehub1";
            string deviceId                   = "d1";
            string moduleId                   = "m1";
            var    underlyingAuthenticator    = Mock.Of <IAuthenticator>();
            var    deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>();
            string key = GetKey();
            var    deviceServiceIdentity = new ServiceIdentity(deviceId, "1234", new string[0], new ServiceAuthentication(new SymmetricKeyAuthentication(key, GetKey())), ServiceIdentityStatus.Enabled);
            var    moduleServiceIdentity = new ServiceIdentity(deviceId, moduleId, "e1", new List <string>(), "1234", new string[0], new ServiceAuthentication(new SymmetricKeyAuthentication(GetKey(), GetKey())), ServiceIdentityStatus.Enabled);

            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(It.Is <string>(i => i == $"{deviceId}/{moduleId}")))
            .ReturnsAsync(Option.Some(moduleServiceIdentity));
            deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == $"{deviceId}/{moduleId}")))
            .ReturnsAsync(Option.Some($"{deviceId}/{moduleId}"));
            deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(It.Is <string>(i => i == deviceId)))
            .ReturnsAsync(Option.Some(deviceServiceIdentity));
            deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == deviceId)))
            .ReturnsAsync(Option.Some(deviceId));

            IAuthenticator authenticator = new DeviceScopeTokenAuthenticator(deviceScopeIdentitiesCache.Object, iothubHostName, edgehubHostName, underlyingAuthenticator, true, true);

            var    identity         = Mock.Of <IModuleIdentity>(d => d.DeviceId == deviceId && d.ModuleId == moduleId && d.Id == $"{deviceId}/{moduleId}");
            string token            = GetDeviceToken(iothubHostName, deviceId, moduleId, key);
            var    tokenCredentials = Mock.Of <ITokenCredentials>(t => t.Identity == identity && t.Token == token);

            // Act
            bool isAuthenticated = await authenticator.AuthenticateAsync(tokenCredentials);

            // Assert
            Assert.True(isAuthenticated);
            Mock.Get(underlyingAuthenticator).VerifyAll();
        }