1
0
mirror of https://github.com/bitwarden/server synced 2025-12-20 02:03:46 +00:00
Files
server/src/Core/Identity/DuoTokenProvider.cs
2017-07-06 16:56:12 -04:00

105 lines
3.4 KiB
C#

using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Bit.Core.Utilities.Duo;
using System.Collections.Generic;
using System.Net.Http;
namespace Bit.Core.Identity
{
public class DuoTokenProvider : IUserTwoFactorTokenProvider<User>
{
public Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
{
if(!user.Premium)
{
return Task.FromResult(false);
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo);
var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.Duo)
&& !string.IsNullOrWhiteSpace((string)provider?.MetaData["UserId"]);
return Task.FromResult(canGenerate);
}
/// <param name="purpose">Ex: "auto", "push", "passcode:123456", "sms", "phone"</param>
public async Task<string> GenerateAsync(string purpose, UserManager<User> manager, User user)
{
if(!user.Premium)
{
return Task.FromResult<string>(null);
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo);
var duoClient = new DuoApi((string)provider.MetaData["IKey"], (string)provider.MetaData["SKey"],
(string)provider.MetaData["Host"]);
var parts = purpose.Split(':');
var parameters = new Dictionary<string, string>
{
["async"] = "1",
["user_id"] = (string)provider.MetaData["UserId"],
["factor"] = parts[0]
};
if(parameters["factor"] == "passcode" && parts.Length > 1)
{
parameters["passcode"] = parts[1];
}
else
{
parameters["device"] = "auto";
}
try
{
var response = await duoClient.JSONApiCallAsync<Dictionary<string, object>>(HttpMethod.Post,
"/auth/v2/auth", parameters);
if(response.ContainsKey("txid"))
{
var txId = response["txid"] as string;
return txId;
}
}
catch(DuoException) { }
return null;
}
public async Task<bool> ValidateAsync(string purpose, string token, UserManager<User> manager, User user)
{
if(!user.Premium)
{
return false;
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo);
var duoClient = new DuoApi((string)provider.MetaData["IKey"], (string)provider.MetaData["SKey"],
(string)provider.MetaData["Host"]);
var parameters = new Dictionary<string, string>
{
["txid"] = token
};
try
{
var response = await duoClient.JSONApiCallAsync<Dictionary<string, object>>(HttpMethod.Get,
"/auth/v2/auth_status", parameters);
var result = response["result"] as string;
return string.Equals(result, "allow");
}
catch(DuoException)
{
// TODO: We might want to return true in some cases? What if Duo is down?
}
return false;
}
}
}