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

feat: add TryLogin(string, SecureString) methods #143

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
33 changes: 26 additions & 7 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,31 @@ name: CI
on: [push]

jobs:
build:

build-linux:
runs-on: ubuntu-latest


steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
- run: dotnet build MetasysServices --configuration Release
- run: dotnet test MetasysServicesLinux.sln

build-macos:
runs-on: macos-latest

steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: "6.0.x"
- run: dotnet build MetasysServices --configuration Release
- run: dotnet test MetasysServicesLinux.sln

build-windows:
runs-on: windows-latest

steps:
- uses: actions/checkout@master
- uses: actions/setup-dotnet@v1
- run: dotnet build MetasysServices --configuration Release
- run: dotnet test
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
- run: dotnet build MetasysServices --configuration Release
- run: dotnet test MetasysServices.sln
1 change: 1 addition & 0 deletions MetasysSecrets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nupkg/
28 changes: 28 additions & 0 deletions MetasysSecrets/MetasysSecrets.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<ProjectReference Include="..\MetasysServices\MetasysServices.csproj" />
<None Include="./README.md" Pack="true" PackagePath="/" />
</ItemGroup>

<PropertyGroup>
<PackageId>JohnsonControls.MetasysSecrets</PackageId>
<Version>1.0.0-alpha2</Version>
<Authors>Johnson Controls PLC</Authors>
<Description>A cross platform cli tool for adding Metasys passwords to your operating system credential manager</Description>
<PackageTags>secrets;secret;cli;metasys</PackageTags>
<PackageReleaseNotes>Initial Release for macOS, Linux and Windows. The Linux version has a dependency on libsecret-tools</PackageReleaseNotes>
<RepositoryUrl>https://github.com/jci-metasys/basic-services-dotnet/tree/master/MetasysSecrets/</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<OutputType>Exe</OutputType>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackAsTool>true</PackAsTool>
<ToolCommandName>metasys-secrets</ToolCommandName>
<PackageOutputPath>./nupkg</PackageOutputPath>
</PropertyGroup>

</Project>
91 changes: 91 additions & 0 deletions MetasysSecrets/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// See https://aka.ms/new-console-template for more information
using System.Runtime.InteropServices;
using System.Security;
using JohnsonControls.Metasys.BasicServices;

if (args.Length != 3 || !(args[0] is "add" or "delete"))
{
WriteUsage();
return;
}


switch (args[0])
{
case "add":
var password = GetPassword();
SecretStore.AddOrReplacePassword(args[1], args[2], password);
break;
// case "lookup":
// if (SecretStore.TryGetPassword(args[1], args[2], out SecureString securePassword))
// {
// Console.WriteLine(ConvertToPlainText(securePassword));
// }
// break;
case "delete":
SecretStore.DeletePassword(args[1], args[2]);
break;
default:
break;
}

string ConvertToPlainText(SecureString secureString)

Check warning on line 32 in MetasysSecrets/Program.cs

View workflow job for this annotation

GitHub Actions / build-macos

The local function 'ConvertToPlainText' is declared but never used

Check warning on line 32 in MetasysSecrets/Program.cs

View workflow job for this annotation

GitHub Actions / build-macos

The local function 'ConvertToPlainText' is declared but never used

Check warning on line 32 in MetasysSecrets/Program.cs

View workflow job for this annotation

GitHub Actions / build-linux

The local function 'ConvertToPlainText' is declared but never used

Check warning on line 32 in MetasysSecrets/Program.cs

View workflow job for this annotation

GitHub Actions / build-linux

The local function 'ConvertToPlainText' is declared but never used
{
IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString);
return Marshal.PtrToStringUni(unmanagedString) ?? "";
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}

void WriteUsage()
{
Console.WriteLine("Usage:");
Console.WriteLine(" metasys-secret add {host} {username}");
Console.WriteLine(" metasys-secret delete {host} {username}");
return;
}

SecureString GetPassword()
{
SecureString password = new SecureString();
if (Console.IsInputRedirected)
{
var input = Console.ReadLine();
input?.ToCharArray().ToList().ForEach(password.AppendChar);
return password;
}
Console.Write("Enter your password: ");

while (true)
{

ConsoleKeyInfo key = Console.ReadKey(intercept: true);
if (key.Key == ConsoleKey.Enter)
{
break;
}
else if (key.Key == ConsoleKey.Backspace)
{
if (password.Length > 0)
{
password.RemoveAt(password.Length - 1);
// backup, write a space, and back up again
Console.Write("\b \b");
}
}
else
{
password.AppendChar(key.KeyChar);
Console.Write("*");
}
}
Console.WriteLine();
password.MakeReadOnly();
return password;
}
99 changes: 99 additions & 0 deletions MetasysSecrets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Metasys Secrets

A cli for adding metasys passwords to your operating system credential manager.
These credentials can then be retrieved by your applications using
[SecretStore](../MetasysServices/Credentials/Secrets.cs) and the password can be
securely passed to `MetasysClient.TryLogin` method of
[basic-services-dotnet](../README.md).

## Installation

You'll need a modern version of
[dotnet](https://dotnet.microsoft.com/en-us/download). Both .Net 6.0 and .Net
8.0 are supported.

```bash
dotnet tool install --global JohnsonControls.MetasysSecrets
```

## Usage

There are three subcommands `add`, `lookup` and `delete` as shown below. Each
takes a `hostName` and `userName` for arguments.

```bash
metasys-secrets add <hostName> <userName>
metasys-secrets lookup <hostName> <userName>
metasys-secrets delete <hostName> <userName>
```

### Examples

In these examples we'll assume that the `hostName` is
`my-ads-server.company.com` and the `userName` is `api-service-account`.

### Save a Password

To save the password

```bash
> metasys-secrets add my-ads-server.company.com api-service-account
Enter your password: *******
```

Notice you are prompted for your password. If you really want to do it all on
one line you can do it like this.

```bash
echo "thepassword" | metasys-secrets add my-ads-server.company.com api-service-account
```

> [!Warning]\
> Be careful with this approach as your password is now shown in plain text and will
> be stored in your shell history. It's not recommended for production environments.

### Delete a Password

To delete a password from your credential manager you can do

```bash
metasys-secrets delete <hostName> <userName>
```

### Display a Password

To read a password from the credential manager you can do

```bash
metasys-secrets lookup <hostName> <userName>
```

> [!Warning]\
> Be careful with this approach as your password is now shown in plain text.It's
> not recommended for production environments. You may choose to use the GUI tool
> for your operating system instead.

## Credential Managers

The credential manager that is used depends on the operating system you are
using.

### Windows

On Windows the passwords are saved in the Windows Credential Manager.

### macOS

On macOS the passwords are saved in the macOS Keychain

### Linux

On Linux the passwords are saved using `libsecret` and it relies on the linux
command line tool `secret-tool`. To install that tool depends on the
distribution you are using.

On Debian/Ubuntu you can install it like this

```bash
sudo apt install libsecret-tools
```
Loading
Loading