diff --git a/src/System.Security.Principal.Windows/src/Configurations.props b/src/System.Security.Principal.Windows/src/Configurations.props
index 54a08cdb99ed..d022d94deb57 100644
--- a/src/System.Security.Principal.Windows/src/Configurations.props
+++ b/src/System.Security.Principal.Windows/src/Configurations.props
@@ -5,6 +5,8 @@
netstandard;
netcoreapp2.0-Windows_NT;
netcoreapp2.0-Unix;
+ netcoreapp2.1-Windows_NT;
+ netcoreapp2.1-Unix;
net461-Windows_NT;
@@ -15,4 +17,4 @@
netfx-Windows_NT;
-
\ No newline at end of file
+
diff --git a/src/System.Security.Principal.Windows/src/PinvokeAnalyzerExceptionList.analyzerdata.netcoreapp2.1 b/src/System.Security.Principal.Windows/src/PinvokeAnalyzerExceptionList.analyzerdata.netcoreapp2.1
new file mode 100644
index 000000000000..6aad19cc39ff
--- /dev/null
+++ b/src/System.Security.Principal.Windows/src/PinvokeAnalyzerExceptionList.analyzerdata.netcoreapp2.1
@@ -0,0 +1 @@
+advapi32.dll!LsaNtStatusToWinError
diff --git a/src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj b/src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj
index 345d3aed719b..e0e538da06e2 100644
--- a/src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj
+++ b/src/System.Security.Principal.Windows/src/System.Security.Principal.Windows.csproj
@@ -6,7 +6,7 @@
true
true
SR.PlatformNotSupported_Principal
- net461-Windows_NT-Debug;net461-Windows_NT-Release;netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;netcoreapp2.0-Unix-Debug;netcoreapp2.0-Unix-Release;netcoreapp2.0-Windows_NT-Debug;netcoreapp2.0-Windows_NT-Release;netfx-Windows_NT-Debug;netfx-Windows_NT-Release;netstandard-Debug;netstandard-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release
+ net461-Windows_NT-Debug;net461-Windows_NT-Release;netcoreapp-Unix-Debug;netcoreapp-Unix-Release;netcoreapp-Windows_NT-Debug;netcoreapp-Windows_NT-Release;netcoreapp2.0-Unix-Debug;netcoreapp2.0-Unix-Release;netcoreapp2.0-Windows_NT-Debug;netcoreapp2.0-Windows_NT-Release;netcoreapp2.1-Unix-Debug;netcoreapp2.1-Unix-Release;netcoreapp2.1-Windows_NT-Debug;netcoreapp2.1-Windows_NT-Release;netfx-Windows_NT-Debug;netfx-Windows_NT-Release;netstandard-Debug;netstandard-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release
diff --git a/src/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs b/src/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs
index 09435371977a..98f9a331fb65 100644
--- a/src/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs
+++ b/src/System.Security.Principal.Windows/src/System/Security/Principal/SID.cs
@@ -792,21 +792,44 @@ public override string ToString()
{
if (_sddlForm == null)
{
- StringBuilder result = new StringBuilder();
-
//
- // Typecasting of _IdentifierAuthority to a long below is important, since
+ // Typecasting of _IdentifierAuthority to a ulong below is important, since
// otherwise you would see this: "S-1-NTAuthority-32-544"
//
- result.Append("S-1-").Append((long)_identifierAuthority);
-
+#if netcoreapp20
+ StringBuilder result = new StringBuilder();
+ result.Append("S-1-").Append((ulong)_identifierAuthority);
for (int i = 0; i < SubAuthorityCount; i++)
{
result.Append('-').Append((uint)(_subAuthorities[i]));
}
-
_sddlForm = result.ToString();
+#else
+ // length of buffer calculation
+ // prefix = "S-1-".Length: 4;
+ // authority: ulong.MaxValue.ToString("D") : 20;
+ // subauth = MaxSubAuthorities * ( uint.MaxValue.ToString("D").Length + '-'.Length ): 15 * (10+1): 165;
+ // max possible length = 4 + 20 + 165: 189
+ Span result = stackalloc char[189];
+ result[0] = 'S';
+ result[1] = '-';
+ result[2] = '1';
+ result[3] = '-';
+ int written;
+ int length = 4;
+ ((ulong)_identifierAuthority).TryFormat(result.Slice(length), out written);
+ length += written;
+ int[] values = _subAuthorities;
+ for (int index = 0; index < values.Length; index++)
+ {
+ result[length] = '-';
+ length += 1;
+ ((uint)values[index]).TryFormat(result.Slice(length), out written);
+ length += written;
+ }
+ _sddlForm = result.Slice(0, length).ToString();
+#endif
}
return _sddlForm;
@@ -910,9 +933,9 @@ public override IdentityReference Translate(Type targetType)
}
}
- #endregion
+#endregion
- #region Operators
+#region Operators
public static bool operator ==(SecurityIdentifier left, SecurityIdentifier right)
{
@@ -938,9 +961,9 @@ public override IdentityReference Translate(Type targetType)
return !(left == right);
}
- #endregion
+#endregion
- #region IComparable implementation
+#region IComparable implementation
public int CompareTo(SecurityIdentifier sid)
{
@@ -982,9 +1005,9 @@ public int CompareTo(SecurityIdentifier sid)
return 0;
}
- #endregion
+#endregion
- #region Public Methods
+#region Public Methods
internal int GetSubAuthority(int index)
{
@@ -1220,6 +1243,6 @@ internal static IdentityReferenceCollection Translate(IdentityReferenceCollectio
throw new ArgumentException(SR.IdentityReference_MustBeIdentityReference, nameof(targetType));
}
- #endregion
+#endregion
}
}
diff --git a/src/System.Security.Principal.Windows/tests/SecurityIdentifierTests.cs b/src/System.Security.Principal.Windows/tests/SecurityIdentifierTests.cs
new file mode 100644
index 000000000000..9ed06a03f2da
--- /dev/null
+++ b/src/System.Security.Principal.Windows/tests/SecurityIdentifierTests.cs
@@ -0,0 +1,92 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Security.Principal;
+using Xunit;
+
+public class SecurityIdentifierTests
+{
+ [Fact]
+ public void ValidateGetCurrentUser()
+ {
+ using (WindowsIdentity identity = WindowsIdentity.GetCurrent(false))
+ {
+ Assert.NotNull(identity.User);
+ }
+ }
+
+ [Fact]
+ public void ValidateToString()
+ {
+ string sddl = null;
+ using (WindowsIdentity me = WindowsIdentity.GetCurrent(false))
+ {
+ sddl = me.User.ToString();
+ }
+
+ Assert.NotNull(sddl);
+ Assert.NotEmpty(sddl);
+ Assert.StartsWith("S-1-5-", sddl); // sid prefix, version 1, user account type
+ Assert.NotEqual('-', sddl[sddl.Length - 1]);
+
+ string[] parts = sddl.Substring(6).Split('-');
+
+ Assert.NotNull(parts);
+ Assert.NotEmpty(parts);
+
+ Assert.All(parts, part => uint.TryParse(part, out uint _));
+ }
+
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer), nameof(PlatformDetection.IsNotWindowsServerCore))]
+ public void ValidateToStringUsingWhoami()
+ {
+ string librarySid = null;
+ using (WindowsIdentity me = WindowsIdentity.GetCurrent(false))
+ {
+ librarySid = me.User.ToString();
+ }
+
+ string windowsSid = null;
+ string processArguments = " /user";
+ // Call whois to get current sid
+ Process whoamiProcess = new Process();
+ whoamiProcess.StartInfo.FileName = "whoami.exe"; // whoami.exe is in system32, should already be on path
+ whoamiProcess.StartInfo.Arguments = " " + processArguments;
+ whoamiProcess.StartInfo.CreateNoWindow = true;
+ whoamiProcess.StartInfo.UseShellExecute = false;
+ whoamiProcess.StartInfo.RedirectStandardOutput = true;
+ whoamiProcess.Start();
+ string output = whoamiProcess.StandardOutput.ReadToEnd();
+ whoamiProcess.WaitForExit();
+
+ if (whoamiProcess.ExitCode == 0)
+ {
+ int startSid = output.IndexOf("S-1-5-");
+ int endSid = 0;
+ if (startSid >= 0)
+ {
+ int length = Math.Min(output.Length - startSid, librarySid.Length);
+ windowsSid = output.Substring(startSid, length);
+
+ if (output.Length > startSid + length)
+ {
+ Assert.True(char.IsWhiteSpace(output[startSid + length]));
+ }
+ }
+ if (endSid > startSid)
+ {
+ windowsSid = output.Substring(startSid, (endSid - startSid));
+ }
+ }
+ Assert.NotNull(windowsSid);
+ Assert.NotEmpty(windowsSid);
+ Assert.NotNull(librarySid);
+ Assert.NotEmpty(librarySid);
+
+ Assert.Equal(windowsSid, librarySid);
+ }
+}
+
diff --git a/src/System.Security.Principal.Windows/tests/System.Security.Principal.Windows.Tests.csproj b/src/System.Security.Principal.Windows/tests/System.Security.Principal.Windows.Tests.csproj
index e2b00270f274..4fd1b7cc8fc4 100644
--- a/src/System.Security.Principal.Windows/tests/System.Security.Principal.Windows.Tests.csproj
+++ b/src/System.Security.Principal.Windows/tests/System.Security.Principal.Windows.Tests.csproj
@@ -5,6 +5,7 @@
+