Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add YubiKey authentication functionality #1378

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions src/XIVLauncher/Accounts/YubiAuth.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Serilog;
using Yubico.YubiKey;
using Yubico.YubiKey.Oath;
using Yubico.PlatformInterop;

namespace XIVLauncher.Accounts
{
public class YubiAuth
{
private const string ISSUER = "XIVLauncher";
private const string ACCOUNT_NAME = "FFXIV";
private const CredentialType AUTH_TYPE = CredentialType.Totp;
private const CredentialPeriod TIME_PERIOD = CredentialPeriod.Period30;
private const byte NUM_DIGITS = 6;
private static string username = "";

private static IYubiKeyDevice _yubiKey;
public YubiKeyDeviceListener DeviceListener;
public YubiAuth()
{
FindYubiDevice();
DeviceListener = YubiKeyDeviceListener.Instance;
}

public static void SetUsername(string name)
{
username = name;
}
public static string GetUsername()
{
return username;
}
public string GetAccountName()
{
return ACCOUNT_NAME + "-" + username;
}

//Generates generic credential
public Credential BuildCredential()
{
var credentialTotp = new Credential
{
Issuer = ISSUER,
AccountName = GetAccountName(),
Type = AUTH_TYPE,
Period = TIME_PERIOD,
Digits = NUM_DIGITS,
};
return credentialTotp;
}

//Generates credential to be put onto user's YubiKey
public Credential BuildCredential(string key, bool useTouch)
{
var credentialTotp = new Credential
{
Issuer = ISSUER,
AccountName = GetAccountName(),
Type = AUTH_TYPE,
Period = TIME_PERIOD,
Secret = key,
Digits = NUM_DIGITS,
RequiresTouch = useTouch,
};
return credentialTotp;
}

//Finds YubiKey(s) that are plugged into a USB port
public void FindYubiDevice()
{
//Find YubiKey device
try
{
if (_yubiKey == null)
{
IEnumerable<IYubiKeyDevice> keys = YubiKeyDevice.FindByTransport(Transport.UsbSmartCard);
SetYubiDevice(keys.First());
}
}
catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException)
{
Log.Debug("No YubiKey device was detected");
Log.Debug(ex.ToString());
}

}

public IYubiKeyDevice GetYubiDevice()
{
return _yubiKey;
}

public void SetYubiDevice(IYubiKeyDevice yubiKeyDevice)
{
_yubiKey = yubiKeyDevice;
}

//Checks for existing credentials on user's YubiKey that match the XIVLauncher generic credential
public bool CheckForCredential(OathSession session)
{
try
{
IList<Credential> creds = session.GetCredentials().Where(credential => credential.Issuer == ISSUER && credential.AccountName == GetAccountName()).ToList();
if (creds != null && creds.Count != 0)
{
return true;
}
return false;
}
catch (SCardException)
{
Log.Error("YubiKey was removed during GET operation.");
return false;
}
}

//Adds the user's credential onto their YubiKey device
public void CreateEntry(Credential cred)
{
try
{
new OathSession(_yubiKey).AddCredential(cred);
Log.Debug("Successfully created new credential " + cred.Name);
}
catch (SCardException)
{
Log.Error("YubiKey was removed during ADD operation");
}

}

}


}
31 changes: 31 additions & 0 deletions src/XIVLauncher/Directory.Build.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project>
<Choose>
<!-- If x86 architecture -->
<When Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X86' OR '$(Platform)' == 'x86'">
<ItemGroup>
<PackageReference Include="Yubico.NativeShims" Version="1.6.1">
<PrivateAssets>build</PrivateAssets>
</PackageReference>
<Content Include="$(NugetPackageRoot)\yubico.nativeshims\1.6.1\runtimes\win-x86\native\Yubico.NativeShims.dll">
<Link>Yubico.NativeShims.dll</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
</ItemGroup>
</When>

<!-- If x64 architecture -->
<When Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)' == 'X64' OR '$(Platform)' == 'x64'">
<ItemGroup>
<PackageReference Include="Yubico.NativeShims" Version="1.6.1">
<PrivateAssets>build</PrivateAssets>
</PackageReference>
<Content Include="$(NugetPackageRoot)\yubico.nativeshims\1.6.1\runtimes\win-x64\native\Yubico.NativeShims.dll">
<Link>Yubico.NativeShims.dll</Link>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
</ItemGroup>
</When>
</Choose>
</Project>
3 changes: 2 additions & 1 deletion src/XIVLauncher/Resources/LICENSE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -724,4 +724,5 @@ System.ValueTuple https://github.com/dotnet/corefx/blob/
aria2 https://github.com/aria2/aria2/blob/master/COPYING
Spooky https://github.com/Yortw/Spooky/blob/master/LICENSE
AriaNet https://creativecommons.org/licenses/by-nc-sa/3.0/au/
SharedMemory https://github.com/spazzarama/SharedMemory/blob/master/LICENSE.md
SharedMemory https://github.com/spazzarama/SharedMemory/blob/master/LICENSE.md
Yubico.NET.SDK https://github.com/Yubico/Yubico.NET.SDK/blob/develop/LICENSE.txt
1 change: 1 addition & 0 deletions src/XIVLauncher/Settings/ILauncherSettingsV3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public interface ILauncherSettingsV3
bool InGameAddonEnabled { get; set; }
DalamudLoadMethod? InGameAddonLoadMethod { get; set; }
bool OtpServerEnabled { get; set; }
bool OtpYubiKeyEnabled { get; set; }
ClientLanguage? Language { get; set; }
LauncherLanguage? LauncherLanguage { get; set; }
string CurrentAccountId { get; set; }
Expand Down
Loading