public async Task <bool> AuthenticateAsync(string id, Option <string> modelId, Option <string> authChain) { try { // See if we received direct credentials for the target identity bool hasToken = this.clientTokens.TryGetValue(id, out ClientToken clientToken); // Otherwise, this could be a child Edge acting OnBehalfOf of the target, // in which case we would have the actor's credentials instead if (!hasToken) { Option <string> actorDeviceId = AuthChainHelpers.GetActorDeviceId(authChain); hasToken = actorDeviceId.Map(actor => this.clientTokens.TryGetValue($"{actor}/{CoreConstants.EdgeHubModuleId}", out clientToken)).GetOrElse(false); } if (hasToken) { // Lock the auth-state check and the auth call to avoid // redundant calls into the authenticator using (await this.identitySyncLock.LockAsync()) { if (this.authenticatedClients.ContainsKey(id)) { // We've previously authenticated this client already return(true); } else { IClientCredentials clientCredentials = this.clientCredentialsFactory.GetWithSasToken( clientToken.DeviceId, clientToken.ModuleId.OrDefault(), string.Empty, clientToken.Token, true, modelId, authChain); if (await this.authenticator.AuthenticateAsync(clientCredentials)) { // Authentication success, add an entry for the authenticated // client identity, the value in the dictionary doesn't matter // as we're effectively using it as a thread-safe HashSet this.authenticatedClients[id] = default(byte); // No need to add the new credentials to the cache, as the // authenticator already implicitly handles it return(true); } } } } return(false); } catch (Exception e) { Events.ErrorAuthenticatingIdentity(id, e); return(false); } }
public async Task <IDeviceIdentity> GetAsync(string clientId, string username, string password, EndPoint clientAddress) { try { Preconditions.CheckNonWhiteSpace(username, nameof(username)); Preconditions.CheckNonWhiteSpace(clientId, nameof(clientId)); ClientInfo clientInfo = this.usernameParser.Parse(username); clientInfo.ModelId.ForEach(async m => await this.metadataStore.SetModelId(clientInfo.DeviceId, m)); IClientCredentials deviceCredentials = null; Option <IClientCredentials> actorCredentials = Option.None <IClientCredentials>(); if (!string.IsNullOrEmpty(password)) { deviceCredentials = this.clientCredentialsFactory.GetWithSasToken(clientInfo.DeviceId, clientInfo.ModuleId, clientInfo.DeviceClientType, password, false, clientInfo.ModelId, clientInfo.AuthChain); // For OnBehalfOf connections, we'll get the token for the actor EdgeHub instead // of the actual leaf/module, so we need to construct the credentials accordingly Option <string> actorDeviceIdOption = AuthChainHelpers.GetActorDeviceId(clientInfo.AuthChain); actorCredentials = actorDeviceIdOption.Map(actorDeviceId => this.clientCredentialsFactory.GetWithSasToken( actorDeviceId, Microsoft.Azure.Devices.Edge.Hub.Core.Constants.EdgeHubModuleId, clientInfo.DeviceClientType, password, false, clientInfo.ModelId, clientInfo.AuthChain)); } else if (this.remoteCertificate.HasValue) { if (!this.clientCertAuthAllowed) { Events.CertAuthNotEnabled(clientInfo.DeviceId, clientInfo.ModuleId); return(UnauthenticatedDeviceIdentity.Instance); } this.remoteCertificate.ForEach( cert => { deviceCredentials = this.clientCredentialsFactory.GetWithX509Cert( clientInfo.DeviceId, clientInfo.ModuleId, clientInfo.DeviceClientType, cert, this.remoteCertificateChain, clientInfo.ModelId, Option.None <string>()); }); } else { Events.AuthNotFound(clientInfo.DeviceId, clientInfo.ModuleId); return(UnauthenticatedDeviceIdentity.Instance); } if (deviceCredentials == null || !clientId.Equals(deviceCredentials.Identity.Id, StringComparison.Ordinal) || !await this.authenticator.AuthenticateAsync(actorCredentials.GetOrElse(deviceCredentials))) { Events.Error(clientId, username); return(UnauthenticatedDeviceIdentity.Instance); } await this.metadataStore.SetMetadata(deviceCredentials.Identity.Id, clientInfo.DeviceClientType, clientInfo.ModelId); Events.Success(clientId, username); return(new ProtocolGatewayIdentity(deviceCredentials, clientInfo.ModelId)); } catch (Exception ex) { Events.ErrorCreatingIdentity(ex); throw; } }