Initial half-port of PAPE extension.
[dotnetoauth.git] / src / DotNetOpenAuth / OpenId / Extensions / ProviderAuthenticationPolicy / PolicyRequest.cs
blobffaec906aa3489e480c6be082a073f5f39510031
1 //-----------------------------------------------------------------------
2 // <copyright file="PolicyRequest.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
4 // </copyright>
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy {
8 using System;
9 using System.Collections.Generic;
10 using System.Text;
11 using System.Globalization;
12 using System.Diagnostics;
13 using DotNetOpenAuth.OpenId.RelyingParty;
14 using DotNetOpenAuth.Messaging;
16 /// <summary>
17 /// The PAPE request part of an OpenID Authentication request message.
18 /// </summary>
19 public sealed class PolicyRequest : ExtensionBase, IMessageWithEvents {
20 [MessagePart("preferred_auth_policies", IsRequired = true)]
21 private string preferredPoliciesString;
23 /// <summary>
24 /// Initializes a new instance of the <see cref="PolicyRequest"/> class.
25 /// </summary>
26 public PolicyRequest()
27 : base(new Version(1, 0), Constants.TypeUri, null) {
28 PreferredPolicies = new List<string>(1);
29 PreferredAuthLevelTypes = new List<string>(1);
32 /// <summary>
33 /// Optional. If the End User has not actively authenticated to the OP within
34 /// the number of seconds specified in a manner fitting the requested policies,
35 /// the OP SHOULD authenticate the End User for this request.
36 /// </summary>
37 /// <remarks>
38 /// The OP should realize that not adhering to the request for re-authentication
39 /// most likely means that the End User will not be allowed access to the
40 /// services provided by the RP. If this parameter is absent in the request,
41 /// the OP should authenticate the user at its own discretion.
42 /// </remarks>
43 [MessagePart("max_auth_age", IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))]
44 public TimeSpan? MaximumAuthenticationAge { get; set; }
46 /// <summary>
47 /// Zero or more authentication policy URIs that the OP SHOULD conform to when authenticating the user. If multiple policies are requested, the OP SHOULD satisfy as many as it can.
48 /// </summary>
49 /// <value>List of authentication policy URIs obtainable from the <see cref="AuthenticationPolicies"/> class or from a custom list.</value>
50 /// <remarks>
51 /// If no policies are requested, the RP may be interested in other information such as the authentication age.
52 /// </remarks>
53 public IList<string> PreferredPolicies { get; private set; }
55 /// <summary>
56 /// Zero or more name spaces of the custom Assurance Level the RP requests, in the order of its preference.
57 /// </summary>
58 public IList<string> PreferredAuthLevelTypes { get; private set; }
60 /// <summary>
61 /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
62 /// </summary>
63 /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
64 /// <returns>
65 /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
66 /// </returns>
67 /// <exception cref="T:System.NullReferenceException">
68 /// The <paramref name="obj"/> parameter is null.
69 /// </exception>
70 public override bool Equals(object obj) {
71 PolicyRequest other = obj as PolicyRequest;
72 if (other == null) {
73 return false;
76 if (MaximumAuthenticationAge != other.MaximumAuthenticationAge) {
77 return false;
80 if (PreferredPolicies.Count != other.PreferredPolicies.Count) {
81 return false;
84 foreach (string policy in PreferredPolicies) {
85 if (!other.PreferredPolicies.Contains(policy)) {
86 return false;
90 if (PreferredAuthLevelTypes.Count != other.PreferredAuthLevelTypes.Count) {
91 return false;
94 foreach (string authLevel in PreferredAuthLevelTypes) {
95 if (!other.PreferredAuthLevelTypes.Contains(authLevel)) {
96 return false;
100 return true;
103 /// <summary>
104 /// Serves as a hash function for a particular type.
105 /// </summary>
106 /// <returns>
107 /// A hash code for the current <see cref="T:System.Object"/>.
108 /// </returns>
109 public override int GetHashCode() {
110 // TODO: fix this to match Equals
111 return PreferredPolicies.GetHashCode();
114 private static string SerializePolicies(IList<string> policies) {
115 return PapeUtilities.ConcatenateListOfElements(policies);
118 private static string SerializeAuthLevels(IList<string> preferredAuthLevelTypes, AliasManager aliases) {
119 var aliasList = new List<string>();
120 foreach (string typeUri in preferredAuthLevelTypes) {
121 aliasList.Add(aliases.GetAlias(typeUri));
124 return PapeUtilities.ConcatenateListOfElements(aliasList);
127 #region IMessageWithEvents Members
129 /// <summary>
130 /// Called when the message is about to be transmitted,
131 /// before it passes through the channel binding elements.
132 /// </summary>
133 void IMessageWithEvents.OnSending() {
134 var extraData = ((IMessage)this).ExtraData;
135 extraData.Clear();
137 this.preferredPoliciesString = SerializePolicies(this.PreferredPolicies);
139 if (PreferredAuthLevelTypes.Count > 0) {
140 AliasManager authLevelAliases = new AliasManager();
141 authLevelAliases.AssignAliases(PreferredAuthLevelTypes, Constants.AuthenticationLevels.PreferredTypeUriToAliasMap);
143 // Add a definition for each Auth Level Type alias.
144 foreach (string alias in authLevelAliases.Aliases) {
145 extraData.Add(Constants.AuthLevelNamespaceDeclarationPrefix + alias, authLevelAliases.ResolveAlias(alias));
148 // Now use the aliases for those type URIs to list a preferred order.
149 extraData.Add(Constants.RequestParameters.PreferredAuthLevelTypes, SerializeAuthLevels(PreferredAuthLevelTypes, authLevelAliases));
153 /// <summary>
154 /// Called when the message has been received,
155 /// after it passes through the channel binding elements.
156 /// </summary>
157 void IMessageWithEvents.OnReceiving() {
158 var extraData = ((IMessage)this).ExtraData;
160 PreferredPolicies.Clear();
161 string[] preferredPolicies = extraData[Constants.RequestParameters.PreferredAuthPolicies].Split(' ');
162 foreach (string policy in preferredPolicies) {
163 if (policy.Length > 0)
164 PreferredPolicies.Add(policy);
167 PreferredAuthLevelTypes.Clear();
168 AliasManager authLevelAliases = PapeUtilities.FindIncomingAliases(extraData);
169 string preferredAuthLevelAliases;
170 if (extraData.TryGetValue(Constants.RequestParameters.PreferredAuthLevelTypes, out preferredAuthLevelAliases)) {
171 foreach (string authLevelAlias in preferredAuthLevelAliases.Split(' ')) {
172 if (authLevelAlias.Length == 0) continue;
173 PreferredAuthLevelTypes.Add(authLevelAliases.ResolveAlias(authLevelAlias));
178 #endregion