/// <summary> /// Get the native (unmanaged) representation of the list of values in /// the Microsoft.Samples.Cbac.ClaimValue instance. /// </summary> /// <param name="valueType">Type of the value(s) in this instance</param> /// <param name="values">The collection of values each in string format</param> /// <param name="valueCount">Return the count of unique values</param> /// <returns>SafeHGlobalHandle that references a native (unmanaged) /// pointer to values that can be used in the 'Values' field of the /// CLAIM_SECURITY_ATTRIBUTE_V1 structure.</returns> static SafeHGlobalHandle GetRawValues(ClaimValueType valueType, string value, out ULONG valueCount) { const int BASE_OCTAL = 8; const int BASE_DECIMAL = 10; const int BASE_HEX = 16; const string OCTAL_REGEX = "^[+]?0[0-7]+$"; const string HEX_REGEX = "^[+]?0[xX][0-9a-fA-f]+$"; var stringValues = new StringCollection(); valueCount = 1; // // As part of formulating the values in native format, verify that // we do not have duplicates. AuthzModifyClaims fails with // ERROR_ALREADY_EXISTS when duplicate values are specified. // switch (valueType) { case ClaimValueType.Integer: { long[] values = new long[1]; try { int fromBase = BASE_DECIMAL; if (Regex.Match(value, OCTAL_REGEX).Success) { fromBase = BASE_OCTAL; } else if (Regex.Match(value, HEX_REGEX).Success) { fromBase = BASE_HEX; } values[0] = Convert.ToInt64(value, fromBase); return(SafeHGlobalHandle.AllocHGlobal(values)); } catch (Exception e) { throw new BadValueException(string.Format(CultureInfo.CurrentCulture, "Invalid Int value - {0}", value), e); } } case ClaimValueType.Boolean: { long[] values = new long[1]; try { string strValue = value; if (string.Compare(value, "true", StringComparison.OrdinalIgnoreCase) == 0) { strValue = "1"; } else if (string.Compare(value, "false", StringComparison.OrdinalIgnoreCase) == 0) { strValue = "0"; } values[0] = Convert.ToInt64(strValue, CultureInfo.InvariantCulture); return(SafeHGlobalHandle.AllocHGlobal(values)); } catch (Exception e) { throw new BadValueException(string.Format(CultureInfo.CurrentCulture, "Invalid Boolean value - {0}", value), e); } } case ClaimValueType.MultiValuedString: { char[] bracketChars = { '[', ']' }; const string CSV_REGEX = @"# Parse CVS line. Capture next value in named group: 'val' \s* # Ignore leading whitespace. (?: # Group of value alternatives. "" # Either a double quoted string, (?<val> # Capture contents between quotes. [^""]*(""""[^""]*)* # Zero or more non-quotes, allowing ) # doubled "" quotes within string. ""\s* # Ignore whitespace following quote. | (?<val>[^,]+) # Or... One or more non-commas. ) # End value alternatives group. (?:,|$) # Match end is comma or EOS"; if (!value.StartsWith("[", StringComparison.Ordinal) || !value.EndsWith("]", StringComparison.Ordinal)) { throw new BadValueException(string.Format(CultureInfo.CurrentCulture, "Multi-valued String is not enclosed within square brackets: '{0}'", value)); } MatchCollection splitResult = Regex.Matches(value.Trim(bracketChars), CSV_REGEX, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace); if (splitResult.Count == 0) { throw new BadValueException(string.Format(CultureInfo.CurrentCulture, "Ill-formed Multi-valued String: '{0}'", value)); } else { foreach (Match literal in splitResult) { string strVal = literal.Groups["val"].Value.Trim(); if (!stringValues.Contains(strVal)) { if (!string.IsNullOrEmpty(strVal)) { stringValues.Add(strVal); } } else { Helper.ReportDuplicateValue(ClaimValueType.MultiValuedString, literal.Groups["val"].Value); } } } if (stringValues.Count == 0) { throw new BadValueException(string.Format(CultureInfo.CurrentCulture, "No non-empty strings in : '{0}'", value)); } valueCount = (ULONG)stringValues.Count; goto case ClaimValueType.String; } case ClaimValueType.String: { if (stringValues.Count == 0) { string strVal = value.Trim(); if (!string.IsNullOrEmpty(strVal)) { stringValues.Add(strVal); } } var strings = new List <SafeHGlobalHandle>(stringValues.Count); foreach (var stringValue in stringValues) { SafeHGlobalHandle nativeString = SafeHGlobalHandle.AllocHGlobal(stringValue); strings.Add(nativeString); } SafeHGlobalHandle result = SafeHGlobalHandle.AllocHGlobal( strings.Select(n => n.ToIntPtr()) .ToArray()); // // Since the native (managed) representation is an array // of pointers to strings, ensure that these pointers // are being referenced in the uber SafeHGlobalHandle // that represents the array of pointers. // result.AddSubReference(strings); valueCount = (ULONG)strings.Count; return(result); } default: { valueCount = 0; break; } } return(SafeHGlobalHandle.InvalidHandle); }