Hooked up PAPE extension factory methods.
[dotnetoauth.git] / src / DotNetOpenAuth / OpenId / Extensions / ProviderAuthenticationPolicy / PolicyRequest.cs
blob07e58f52a9c7fcbdc42bdad3c8771cecdcfe91bc
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 DotNetOpenAuth.Messaging;
11 using DotNetOpenAuth.OpenId.Messages;
13 /// <summary>
14 /// The PAPE request part of an OpenID Authentication request message.
15 /// </summary>
16 public sealed class PolicyRequest : ExtensionBase, IMessageWithEvents {
17 /// <summary>
18 /// The factory method that may be used in deserialization of this message.
19 /// </summary>
20 internal static readonly OpenIdExtensionFactory.CreateDelegate Factory = (typeUri, data, baseMessage) => {
21 if (typeUri == Constants.TypeUri && baseMessage is SignedResponseRequest) {
22 return new PolicyRequest();
25 return null;
28 [MessagePart("preferred_auth_policies", IsRequired = true)]
29 private string preferredPoliciesString;
31 /// <summary>
32 /// Initializes a new instance of the <see cref="PolicyRequest"/> class.
33 /// </summary>
34 public PolicyRequest()
35 : base(new Version(1, 0), Constants.TypeUri, null) {
36 PreferredPolicies = new List<string>(1);
37 PreferredAuthLevelTypes = new List<string>(1);
40 /// <summary>
41 /// Optional. If the End User has not actively authenticated to the OP within
42 /// the number of seconds specified in a manner fitting the requested policies,
43 /// the OP SHOULD authenticate the End User for this request.
44 /// </summary>
45 /// <remarks>
46 /// The OP should realize that not adhering to the request for re-authentication
47 /// most likely means that the End User will not be allowed access to the
48 /// services provided by the RP. If this parameter is absent in the request,
49 /// the OP should authenticate the user at its own discretion.
50 /// </remarks>
51 [MessagePart("max_auth_age", IsRequired = false, Encoder = typeof(TimespanSecondsEncoder))]
52 public TimeSpan? MaximumAuthenticationAge { get; set; }
54 /// <summary>
55 /// 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.
56 /// </summary>
57 /// <value>List of authentication policy URIs obtainable from the <see cref="AuthenticationPolicies"/> class or from a custom list.</value>
58 /// <remarks>
59 /// If no policies are requested, the RP may be interested in other information such as the authentication age.
60 /// </remarks>
61 public IList<string> PreferredPolicies { get; private set; }
63 /// <summary>
64 /// Zero or more name spaces of the custom Assurance Level the RP requests, in the order of its preference.
65 /// </summary>
66 public IList<string> PreferredAuthLevelTypes { get; private set; }
68 /// <summary>
69 /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
70 /// </summary>
71 /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
72 /// <returns>
73 /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
74 /// </returns>
75 /// <exception cref="T:System.NullReferenceException">
76 /// The <paramref name="obj"/> parameter is null.
77 /// </exception>
78 public override bool Equals(object obj) {
79 PolicyRequest other = obj as PolicyRequest;
80 if (other == null) {
81 return false;
84 if (MaximumAuthenticationAge != other.MaximumAuthenticationAge) {
85 return false;
88 if (PreferredPolicies.Count != other.PreferredPolicies.Count) {
89 return false;
92 foreach (string policy in PreferredPolicies) {
93 if (!other.PreferredPolicies.Contains(policy)) {
94 return false;
98 if (PreferredAuthLevelTypes.Count != other.PreferredAuthLevelTypes.Count) {
99 return false;
102 foreach (string authLevel in PreferredAuthLevelTypes) {
103 if (!other.PreferredAuthLevelTypes.Contains(authLevel)) {
104 return false;
108 return true;
111 /// <summary>
112 /// Serves as a hash function for a particular type.
113 /// </summary>
114 /// <returns>
115 /// A hash code for the current <see cref="T:System.Object"/>.
116 /// </returns>
117 public override int GetHashCode() {
118 // TODO: fix this to match Equals
119 return PreferredPolicies.GetHashCode();
122 private static string SerializePolicies(IList<string> policies) {
123 return PapeUtilities.ConcatenateListOfElements(policies);
126 private static string SerializeAuthLevels(IList<string> preferredAuthLevelTypes, AliasManager aliases) {
127 var aliasList = new List<string>();
128 foreach (string typeUri in preferredAuthLevelTypes) {
129 aliasList.Add(aliases.GetAlias(typeUri));
132 return PapeUtilities.ConcatenateListOfElements(aliasList);
135 #region IMessageWithEvents Members
137 /// <summary>
138 /// Called when the message is about to be transmitted,
139 /// before it passes through the channel binding elements.
140 /// </summary>
141 void IMessageWithEvents.OnSending() {
142 var extraData = ((IMessage)this).ExtraData;
143 extraData.Clear();
145 this.preferredPoliciesString = SerializePolicies(this.PreferredPolicies);
147 if (PreferredAuthLevelTypes.Count > 0) {
148 AliasManager authLevelAliases = new AliasManager();
149 authLevelAliases.AssignAliases(PreferredAuthLevelTypes, Constants.AuthenticationLevels.PreferredTypeUriToAliasMap);
151 // Add a definition for each Auth Level Type alias.
152 foreach (string alias in authLevelAliases.Aliases) {
153 extraData.Add(Constants.AuthLevelNamespaceDeclarationPrefix + alias, authLevelAliases.ResolveAlias(alias));
156 // Now use the aliases for those type URIs to list a preferred order.
157 extraData.Add(Constants.RequestParameters.PreferredAuthLevelTypes, SerializeAuthLevels(PreferredAuthLevelTypes, authLevelAliases));
161 /// <summary>
162 /// Called when the message has been received,
163 /// after it passes through the channel binding elements.
164 /// </summary>
165 void IMessageWithEvents.OnReceiving() {
166 var extraData = ((IMessage)this).ExtraData;
168 PreferredPolicies.Clear();
169 string[] preferredPolicies = extraData[Constants.RequestParameters.PreferredAuthPolicies].Split(' ');
170 foreach (string policy in preferredPolicies) {
171 if (policy.Length > 0)
172 PreferredPolicies.Add(policy);
175 PreferredAuthLevelTypes.Clear();
176 AliasManager authLevelAliases = PapeUtilities.FindIncomingAliases(extraData);
177 string preferredAuthLevelAliases;
178 if (extraData.TryGetValue(Constants.RequestParameters.PreferredAuthLevelTypes, out preferredAuthLevelAliases)) {
179 foreach (string authLevelAlias in preferredAuthLevelAliases.Split(' ')) {
180 if (authLevelAlias.Length == 0) continue;
181 PreferredAuthLevelTypes.Add(authLevelAliases.ResolveAlias(authLevelAlias));
186 #endregion