public async Task <string> GetSubjectFromDeviceGuardSigning(string accessToken, string refreshToken, CancellationToken cancellationToken = default)
        {
            string tempFile = null;

            try
            {
                var cfg = new DeviceGuardConfig
                {
                    AccessToken  = accessToken,
                    RefreshToken = refreshToken
                };

                var helper = new DgssTokenCreator();
                tempFile = await helper.CreateDeviceGuardJsonTokenFile(cfg, cancellationToken).ConfigureAwait(false);

                return(await this.GetSubjectFromDeviceGuardSigning(tempFile, cancellationToken).ConfigureAwait(false));
            }
            finally
            {
                if (tempFile != null && File.Exists(tempFile))
                {
                    ExceptionGuard.Guard(() => File.Delete(tempFile));
                }
            }
        }
Beispiel #2
0
        public async Task <DeviceGuardConfig> SignIn(bool validateSubject = false, CancellationToken cancellationToken = default, IProgress <ProgressData> progress = default)
        {
            var    factory      = new MsixHeroClientFactory();
            string refreshToken = null;
            EventHandler <string> gotRefreshToken = (_, s) =>
            {
                refreshToken = s;
            };

            progress?.Report(new ProgressData(0, "Signing-in..."));

            try
            {
                factory.GotRefreshToken += gotRefreshToken;
                var clientApp = PublicClientApplicationBuilder.Create("4dd963fd-7400-4ce3-bc90-0bed2b65820d")
                                .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
                                .WithHttpClientFactory(factory)
                                .Build();

                await clientApp.GetAccountsAsync().ConfigureAwait(true);

                var result = await clientApp.AcquireTokenInteractive(Scope).WithPrompt(Prompt.ForceLogin).ExecuteAsync(cancellationToken).ConfigureAwait(false);

                var tokens = new DeviceGuardConfig(result.AccessToken, refreshToken);

                if (validateSubject)
                {
                    progress?.Report(new ProgressData(50, "Validating signing capabilities..."));

                    var dgh  = new DeviceGuardHelper();
                    var json = await this.CreateDeviceGuardJsonTokenFile(new DeviceGuardConfig(result.AccessToken, refreshToken), cancellationToken).ConfigureAwait(false);

                    try
                    {
                        // set the result subject.
                        tokens.Subject = await dgh.GetSubjectFromDeviceGuardSigning(json, cancellationToken).ConfigureAwait(false);
                    }
                    finally
                    {
                        if (json != null && File.Exists(json))
                        {
                            File.Delete(json);
                        }
                    }
                }

                return(tokens);
            }
            finally
            {
                factory.GotRefreshToken -= gotRefreshToken;
            }
        }
Beispiel #3
0
        public SecureString CreateDeviceGuardJsonToken(DeviceGuardConfig tokens, CancellationToken cancellationToken = default)
        {
            var secureString = new SecureString();

            var jsonObject = new JObject();

            jsonObject["access_token"]  = tokens.AccessToken;
            jsonObject["refresh_token"] = tokens.RefreshToken;

            foreach (var c in jsonObject.ToString(Formatting.Indented))
            {
                secureString.AppendChar(c);
            }

            return(secureString);
        }
Beispiel #4
0
        public async Task <string> CreateDeviceGuardJsonTokenFile(DeviceGuardConfig tokens, CancellationToken cancellationToken = default)
        {
            var tmpFile = Path.Combine(Path.GetTempPath(), "msixhero-dg-" + Guid.NewGuid().ToString("N").Substring(0, 12) + ".json");

            await using var text = File.Create(tmpFile);
            var jsonObject = new JObject
            {
                ["access_token"]  = tokens.AccessToken,
                ["refresh_token"] = tokens.RefreshToken
            };

            await using var streamWriter = new StreamWriter(text);
            cancellationToken.ThrowIfCancellationRequested();
            await streamWriter.WriteAsync(jsonObject.ToString(Formatting.Indented)).ConfigureAwait(false);

            return(tmpFile);
        }
Beispiel #5
0
        public async Task <DeviceGuardConfig> SignIn(CancellationToken cancellationToken = default, IProgress <ProgressData> progress = null)
        {
            Logger.Info("Signing in to AzureAD...");
            progress?.Report(new ProgressData(50, "Waiting for authentication..."));
            var tokens   = new DeviceGuardConfig();
            var pipeName = "msixhero-" + Guid.NewGuid().ToString("N");

            await using (var namedPipeServer = new NamedPipeServerStream(pipeName, PipeDirection.In))
            {
                var entry = (Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly()).Location;

                // ReSharper disable once AssignNullToNotNullAttribute
                var startPath = Path.Combine(Path.GetDirectoryName(entry), "DGSS", "msixhero-dgss.exe");
                Logger.Debug($"Starting {startPath}...");
                var process = new ProcessStartInfo(
                    startPath,
                    pipeName);

                var tcs = new TaskCompletionSource <int>();

                var start = Process.Start(process);
                if (start == null)
                {
                    throw new InvalidOperationException();
                }

                start.EnableRaisingEvents = true;
                start.Exited += (sender, args) =>
                {
                    tcs.SetResult(start.ExitCode);
                };

                await namedPipeServer.WaitForConnectionAsync(cancellationToken).ConfigureAwait(false);

                var bufferInt = new byte[4];
                await namedPipeServer.ReadAsync(bufferInt, 0, bufferInt.Length, cancellationToken).ConfigureAwait(false);

                var bufferObj = new byte[BitConverter.ToInt32(bufferInt, 0)];
                await namedPipeServer.ReadAsync(bufferObj, 0, bufferObj.Length, cancellationToken).ConfigureAwait(false);

                var text = System.Text.Encoding.UTF8.GetString(bufferObj);
                var obj  = JObject.Parse(text);

                if (obj["exception"] != null)
                {
                    var type      = obj["exception"]["type"]?.Value <string>();
                    var message   = obj["exception"]["message"]?.Value <string>();
                    var errorCode = obj["exception"]["errorCode"]?.Value <string>();

                    Logger.Error($"Got exception (type: {type}, error code: {errorCode}, message: {message}");

                    switch (type)
                    {
                    case nameof(AuthenticationException):
                        throw new AuthenticationException(message);

                    case nameof(MsalException):
                        throw new MsalException(errorCode ?? "1", message);

                    case nameof(MsalClientException):
                        throw new MsalClientException(errorCode ?? "1", message);

                    default:
                        throw new Exception(message);
                    }
                }

                tokens.AccessToken  = obj["access_token"]?.Value <string>();
                tokens.RefreshToken = obj["refresh_token"]?.Value <string>();

                Logger.Info("Got access and refresh token!");
                await tcs.Task.ConfigureAwait(false);
            }

            string tempJsonFile = null;

            try
            {
                var dgh = new DeviceGuardHelper();
                progress?.Report(new ProgressData(75, "Verifying signing capabilities..."));
                tempJsonFile = await this.CreateDeviceGuardJsonTokenFile(tokens, cancellationToken).ConfigureAwait(false);

                progress?.Report(new ProgressData(98, "Verifying signing capabilities..."));
                var subject = await dgh.GetSubjectFromDeviceGuardSigning(tempJsonFile, cancellationToken).ConfigureAwait(false);

                tokens.Subject = subject;
            }
            finally
            {
                if (tempJsonFile != null)
                {
                    Logger.Debug($"Removing {tempJsonFile}...");
                    ExceptionGuard.Guard(() => File.Delete(tempJsonFile));
                }
            }

            return(tokens);
        }