summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy')
-rw-r--r--src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/AuthenticationPolicies.cs7
-rw-r--r--src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/Constants.cs32
-rw-r--r--src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs2
-rw-r--r--src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyRequest.cs93
-rw-r--r--src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs92
5 files changed, 187 insertions, 39 deletions
diff --git a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/AuthenticationPolicies.cs b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/AuthenticationPolicies.cs
index 517525f..f505a9b 100644
--- a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/AuthenticationPolicies.cs
+++ b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/AuthenticationPolicies.cs
@@ -13,6 +13,13 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
/// </remarks>
public static class AuthenticationPolicies {
/// <summary>
+ /// Used in a PAPE response to indicate that no PAPE authentication policies could be satisfied.
+ /// </summary>
+ /// <remarks>
+ /// Used internally by the PAPE extension, so that users don't have to know about it.
+ /// </remarks>
+ internal const string None = "http://schemas.openid.net/pape/policies/2007/06/none";
+ /// <summary>
/// An authentication mechanism where the End User does not provide a shared secret to a party potentially under the control of the Relying Party. (Note that the potentially malicious Relying Party controls where the User-Agent is redirected to and thus may not send it to the End User's actual OpenID Provider).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Phishing")]
diff --git a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/Constants.cs b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/Constants.cs
index 13fc4cf..395ea36 100644
--- a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/Constants.cs
+++ b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/Constants.cs
@@ -12,6 +12,24 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
/// </summary>
internal const string TypeUri = "http://specs.openid.net/extensions/pape/1.0";
/// <summary>
+ /// The namespace alias to use for OpenID 1.x interop, where aliases are not defined in the message.
+ /// </summary>
+ internal const string pape_compatibility_alias = "pape";
+ /// <summary>
+ /// The string to prepend on an Auth Level Type alias definition.
+ /// </summary>
+ internal const string AuthLevelNamespaceDeclarationPrefix = "auth_level.ns.";
+
+ internal static class AuthenticationLevels {
+ internal static readonly IDictionary<string, string> PreferredTypeUriToAliasMap = new Dictionary<string, string> {
+ { NistTypeUri, nist_compatibility_alias },
+ };
+
+ internal const string nist_compatibility_alias = "nist";
+ internal const string NistTypeUri = "http://csrc.nist.gov/publications/nistpubs/800-63/SP800-63V1_0_2.pdf";
+ }
+
+ /// <summary>
/// Parameters to be included with PAPE requests.
/// </summary>
internal static class RequestParameters {
@@ -31,6 +49,10 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
/// If no policies are requested, the RP may be interested in other information such as the authentication age.
/// </remarks>
internal const string PreferredAuthPolicies = "preferred_auth_policies";
+ /// <summary>
+ /// The space separated list of the name spaces of the custom Assurance Level that RP requests, in the order of its preference.
+ /// </summary>
+ internal const string PreferredAuthLevelTypes = "preferred_auth_level_types";
}
/// <summary>
/// Parameters to be included with PAPE responses.
@@ -58,13 +80,11 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
/// </remarks>
internal const string AuthTime = "auth_time";
/// <summary>
- /// Optional. The Assurance Level as defined by the National Institute of Standards and Technology (NIST) in Special Publication 800-63 (Burr, W., Dodson, D., and W. Polk, Ed., “Electronic Authentication Guideline,” April 2006.) [NIST_SP800‑63] corresponding to the authentication method and policies employed by the OP when authenticating the End User.
+ /// The first part of a parameter name that gives the custom string value for
+ /// the assurance level. The second part of the parameter name is the alias for
+ /// that assurance level.
/// </summary>
- /// <value>Integer value between 0 and 4 inclusive.</value>
- /// <remarks>
- /// Level 0 is not an assurance level defined by NIST, but rather SHOULD be used to signify that the OP recognizes the parameter and the End User authentication did not meet the requirements of Level 1. See Appendix A.1.2 (NIST Assurance Levels) for high-level example classifications of authentication methods within the defined levels.
- /// </remarks>
- internal const string NistAuthLevel = "nist_auth_level";
+ internal const string AuthLevelAliasPrefix = "auth_level.";
}
}
}
diff --git a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs
index 2afc118..6358294 100644
--- a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs
+++ b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs
@@ -13,6 +13,8 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
/// before asserting or interpreting what these levels signify, notwithstanding
/// the brief summaries attached to each level in DotNetOpenId documentation.
/// http://csrc.nist.gov/publications/nistpubs/800-63/SP800-63V1_0_2.pdf
+ ///
+ /// See PAPE spec Appendix A.1.2 (NIST Assurance Levels) for high-level example classifications of authentication methods within the defined levels.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Nist")]
public enum NistAssuranceLevel {
diff --git a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyRequest.cs b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyRequest.cs
index 6493db1..eb78e1f 100644
--- a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyRequest.cs
+++ b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyRequest.cs
@@ -14,6 +14,7 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
/// </summary>
public PolicyRequest() {
PreferredPolicies = new List<string>(1);
+ PreferredAuthLevelTypes = new List<string>(1);
}
/// <summary>
@@ -33,6 +34,11 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
public IList<string> PreferredPolicies { get; private set; }
/// <summary>
+ /// Zero or more name spaces of the custom Assurance Level the RP requests, in the order of its preference.
+ /// </summary>
+ public IList<string> PreferredAuthLevelTypes { get; private set; }
+
+ /// <summary>
/// Tests equality between two <see cref="PolicyRequest"/> instances.
/// </summary>
public override bool Equals(object obj) {
@@ -43,6 +49,10 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
foreach(string policy in PreferredPolicies) {
if (!other.PreferredPolicies.Contains(policy)) return false;
}
+ if (PreferredAuthLevelTypes.Count != other.PreferredAuthLevelTypes.Count) return false;
+ foreach (string authLevel in PreferredAuthLevelTypes) {
+ if (!other.PreferredAuthLevelTypes.Contains(authLevel)) return false;
+ }
return true;
}
@@ -66,10 +76,23 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
// Even if empty, this parameter is required as part of the request message.
fields.Add(Constants.RequestParameters.PreferredAuthPolicies, SerializePolicies(PreferredPolicies));
+ if (PreferredAuthLevelTypes.Count > 0) {
+ AliasManager authLevelAliases = new AliasManager();
+ authLevelAliases.AssignAliases(PreferredAuthLevelTypes, Constants.AuthenticationLevels.PreferredTypeUriToAliasMap);
+
+ // Add a definition for each Auth Level Type alias.
+ foreach (string alias in authLevelAliases.Aliases) {
+ fields.Add(Constants.AuthLevelNamespaceDeclarationPrefix + alias, authLevelAliases.ResolveAlias(alias));
+ }
+
+ // Now use the aliases for those type URIs to list a preferred order.
+ fields.Add(Constants.RequestParameters.PreferredAuthLevelTypes, SerializeAuthLevels(PreferredAuthLevelTypes, authLevelAliases));
+ }
+
return fields;
}
- bool IExtensionRequest.Deserialize(IDictionary<string, string> fields, DotNetOpenId.Provider.IRequest request) {
+ bool IExtensionRequest.Deserialize(IDictionary<string, string> fields, DotNetOpenId.Provider.IRequest request, string typeUri) {
if (fields == null) return false;
if (!fields.ContainsKey(Constants.RequestParameters.PreferredAuthPolicies)) return false;
@@ -84,6 +107,16 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
PreferredPolicies.Add(policy);
}
+ PreferredAuthLevelTypes.Clear();
+ AliasManager authLevelAliases = FindIncomingAliases(fields);
+ string preferredAuthLevelAliases;
+ if (fields.TryGetValue(Constants.RequestParameters.PreferredAuthLevelTypes, out preferredAuthLevelAliases)) {
+ foreach (string authLevelAlias in preferredAuthLevelAliases.Split(' ')) {
+ if (authLevelAlias.Length == 0) continue;
+ PreferredAuthLevelTypes.Add(authLevelAliases.ResolveAlias(authLevelAlias));
+ }
+ }
+
return true;
}
@@ -95,23 +128,61 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
get { return Constants.TypeUri; }
}
+ IEnumerable<string> IExtension.AdditionalSupportedTypeUris {
+ get { return new string[0]; }
+ }
+
#endregion
static internal string SerializePolicies(IList<string> policies) {
- Debug.Assert(policies != null);
- StringBuilder policyList = new StringBuilder();
- foreach (string policy in GetUniqueItems(policies)) {
- if (policy.Contains(" ")) {
+ return ConcatenateListOfElements(policies);
+ }
+
+ private static string SerializeAuthLevels(IList<string> preferredAuthLevelTypes, AliasManager aliases) {
+ var aliasList = new List<string>();
+ foreach (string typeUri in preferredAuthLevelTypes) {
+ aliasList.Add(aliases.GetAlias(typeUri));
+ }
+
+ return ConcatenateListOfElements(aliasList);
+ }
+
+ /// <summary>
+ /// Looks at the incoming fields and figures out what the aliases and name spaces for auth level types are.
+ /// </summary>
+ internal static AliasManager FindIncomingAliases(IDictionary<string, string> fields) {
+ AliasManager aliasManager = new AliasManager();
+
+ foreach (var pair in fields) {
+ if (!pair.Key.StartsWith(Constants.AuthLevelNamespaceDeclarationPrefix, StringComparison.Ordinal)) {
+ continue;
+ }
+
+ string alias = pair.Key.Substring(Constants.AuthLevelNamespaceDeclarationPrefix.Length);
+ aliasManager.SetAlias(alias, pair.Value);
+ }
+
+ aliasManager.SetPreferredAliasesWhereNotSet(Constants.AuthenticationLevels.PreferredTypeUriToAliasMap);
+
+ return aliasManager;
+ }
+
+ internal static string ConcatenateListOfElements(IList<string> values) {
+ Debug.Assert(values != null);
+ StringBuilder valuesList = new StringBuilder();
+ foreach (string value in GetUniqueItems(values)) {
+ if (value.Contains(" ")) {
throw new FormatException(string.Format(CultureInfo.CurrentCulture,
- Strings.InvalidUri, policy));
+ Strings.InvalidUri, value));
}
- policyList.Append(policy);
- policyList.Append(" ");
+ valuesList.Append(value);
+ valuesList.Append(" ");
}
- if (policyList.Length > 0)
- policyList.Length -= 1; // remove trailing space
- return policyList.ToString();
+ if (valuesList.Length > 0)
+ valuesList.Length -= 1; // remove trailing space
+ return valuesList.ToString();
}
+
static internal IEnumerable<T> GetUniqueItems<T>(IList<T> list) {
List<T> itemsSeen = new List<T>(list.Count);
foreach (T item in list) {
diff --git a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs
index a30c873..0f5922f 100644
--- a/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs
+++ b/src/DotNetOpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs
@@ -17,6 +17,7 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
/// </summary>
public PolicyResponse() {
ActualPolicies = new List<string>(1);
+ AssuranceLevels = new Dictionary<string, string>(1);
}
/// <summary>
@@ -46,13 +47,37 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
}
}
}
+
+ /// <summary>
+ /// Optional. The Assurance Level as defined by the National Institute of Standards and Technology (NIST) in Special Publication 800-63 (Burr, W., Dodson, D., and W. Polk, Ed., “Electronic Authentication Guideline,” April 2006.) [NIST_SP800‑63] corresponding to the authentication method and policies employed by the OP when authenticating the End User. /// </summary>
+ /// <remarks> /// See PAPE spec Appendix A.1.2 (NIST Assurance Levels) for high-level example classifications of authentication methods within the defined levels. /// </remarks>
+ public NistAssuranceLevel? NistAssuranceLevel {
+ get {
+ string levelString;
+ if (AssuranceLevels.TryGetValue(Constants.AuthenticationLevels.NistTypeUri, out levelString)) {
+ return (NistAssuranceLevel)Enum.Parse(typeof(NistAssuranceLevel), levelString);
+ } else {
+ return null;
+ }
+ }
+ set {
+ if (value != null) {
+ AssuranceLevels[Constants.AuthenticationLevels.NistTypeUri] = ((int)value).ToString(CultureInfo.InvariantCulture);
+ } else {
+ AssuranceLevels.Remove(Constants.AuthenticationLevels.NistTypeUri);
+ }
+ }
+ }
+
/// <summary>
- /// Optional. The Assurance Level as defined by the National Institute of Standards and Technology (NIST) in Special Publication 800-63 (Burr, W., Dodson, D., and W. Polk, Ed., “Electronic Authentication Guideline,” April 2006.) [NIST_SP800‑63] corresponding to the authentication method and policies employed by the OP when authenticating the End User.
+ /// Gets a dictionary where keys are the authentication level type URIs and
+ /// the values are the per authentication level defined custom value.
/// </summary>
/// <remarks>
- /// See PAPE spec Appendix A.1.2 (NIST Assurance Levels) for high-level example classifications of authentication methods within the defined levels.
+ /// A very common key is <see cref="Constants.AuthenticationLevels.NistTypeUri"/>
+ /// and values for this key are available in <see cref="NistAssuranceLevel"/>.
/// </remarks>
- public NistAssuranceLevel? NistAssuranceLevel { get; set; }
+ public IDictionary<string, string> AssuranceLevels { get; private set; }
/// <summary>
/// Tests equality between two <see cref="PolicyResponse"/> instances.
@@ -61,7 +86,10 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
PolicyResponse other = obj as PolicyResponse;
if (other == null) return false;
if (AuthenticationTimeUtc != other.AuthenticationTimeUtc) return false;
- if (NistAssuranceLevel != other.NistAssuranceLevel) return false;
+ if (AssuranceLevels.Count != other.AssuranceLevels.Count) return false;
+ foreach (var pair in AssuranceLevels) {
+ if (!other.AssuranceLevels.Contains(pair)) return false;
+ }
if (ActualPolicies.Count != other.ActualPolicies.Count) return false;
foreach (string policy in ActualPolicies) {
if (!other.ActualPolicies.Contains(policy)) return false;
@@ -81,25 +109,37 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
IDictionary<string, string> IExtensionResponse.Serialize(DotNetOpenId.Provider.IRequest authenticationRequest) {
var fields = new Dictionary<string, string>();
- fields.Add(Constants.ResponseParameters.AuthPolicies, PolicyRequest.SerializePolicies(ActualPolicies));
+ fields.Add(Constants.ResponseParameters.AuthPolicies, SerializePolicies(ActualPolicies));
if (AuthenticationTimeUtc.HasValue) {
fields.Add(Constants.ResponseParameters.AuthTime, AuthenticationTimeUtc.Value.ToUniversalTime().ToString(PermissibleDateTimeFormats[0], CultureInfo.InvariantCulture));
}
- if (NistAssuranceLevel.HasValue) {
- fields.Add(Constants.ResponseParameters.NistAuthLevel, ((int)NistAssuranceLevel).ToString(CultureInfo.InvariantCulture));
+
+ if (AssuranceLevels.Count > 0) {
+ AliasManager aliases = new AliasManager();
+ aliases.AssignAliases(AssuranceLevels.Keys, Constants.AuthenticationLevels.PreferredTypeUriToAliasMap);
+
+ // Add a definition for each Auth Level Type alias.
+ foreach (string alias in aliases.Aliases) {
+ fields.Add(Constants.AuthLevelNamespaceDeclarationPrefix + alias, aliases.ResolveAlias(alias));
+ }
+
+ // Now use the aliases for those type URIs to list the individual values.
+ foreach (var pair in AssuranceLevels) {
+ fields.Add(Constants.ResponseParameters.AuthLevelAliasPrefix + aliases.GetAlias(pair.Key), pair.Value);
+ }
}
return fields;
}
- bool IExtensionResponse.Deserialize(IDictionary<string, string> fields, DotNetOpenId.RelyingParty.IAuthenticationResponse response) {
+ bool IExtensionResponse.Deserialize(IDictionary<string, string> fields, DotNetOpenId.RelyingParty.IAuthenticationResponse response, string typeUri) {
if (fields == null) return false;
if (!fields.ContainsKey(Constants.ResponseParameters.AuthPolicies)) return false;
ActualPolicies.Clear();
string[] actualPolicies = fields[Constants.ResponseParameters.AuthPolicies].Split(' ');
foreach (string policy in actualPolicies) {
- if (policy.Length > 0)
+ if (policy.Length > 0 && policy != AuthenticationPolicies.None)
ActualPolicies.Add(policy);
}
@@ -111,22 +151,18 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
authDateTime.Kind == DateTimeKind.Utc) { // may be unspecified per our option above
AuthenticationTimeUtc = authDateTime;
} else {
- if (TraceUtil.Switch.TraceError)
- Trace.TraceError("Invalid format for {0} parameter: {1}",
- Constants.ResponseParameters.AuthTime, authTime);
+ Logger.ErrorFormat("Invalid format for {0} parameter: {1}",
+ Constants.ResponseParameters.AuthTime, authTime);
}
}
- NistAssuranceLevel = null;
- string nistAuthLevel;
- if (fields.TryGetValue(Constants.ResponseParameters.NistAuthLevel, out nistAuthLevel)) {
- int nistAuthLevelNumber;
- if (int.TryParse(nistAuthLevel, out nistAuthLevelNumber) &&
- nistAuthLevelNumber >= 0 && nistAuthLevelNumber <= 4) {
- NistAssuranceLevel = (NistAssuranceLevel)nistAuthLevelNumber;
- } else {
- if (TraceUtil.Switch.TraceError)
- Trace.TraceError("Invalid NIST level.");
+ AssuranceLevels.Clear();
+ AliasManager authLevelAliases = PolicyRequest.FindIncomingAliases(fields);
+ foreach (string authLevelAlias in authLevelAliases.Aliases) {
+ string authValue;
+ if (fields.TryGetValue(Constants.ResponseParameters.AuthLevelAliasPrefix + authLevelAlias, out authValue)) {
+ string authLevelType = authLevelAliases.ResolveAlias(authLevelAlias);
+ AssuranceLevels[authLevelType] = authValue;
}
}
@@ -141,6 +177,18 @@ namespace DotNetOpenId.Extensions.ProviderAuthenticationPolicy {
get { return Constants.TypeUri; }
}
+ IEnumerable<string> IExtension.AdditionalSupportedTypeUris {
+ get { return new string[0]; }
+ }
+
#endregion
+
+ static internal string SerializePolicies(IList<string> policies) {
+ if (policies.Count == 0) {
+ return AuthenticationPolicies.None;
+ } else {
+ return PolicyRequest.ConcatenateListOfElements(policies);
+ }
+ }
}
}