/// <summary> /// Adds the AX attribute value to the response if it is non-empty. /// </summary> /// <param name="ax">The AX Fetch response to add the attribute value to.</param> /// <param name="typeUri">The attribute type URI in axschema.org format.</param> /// <param name="format">The target format of the actual attribute to write out.</param> /// <param name="value">The value of the attribute.</param> private static void AddAXAttributeValue(FetchResponse ax, string typeUri, AXAttributeFormats format, string value) { if (!string.IsNullOrEmpty(value)) { string targetTypeUri = OpenIdExtensionsInteropHelper.TransformAXFormat(typeUri, format); if (!ax.Attributes.Contains(targetTypeUri)) { ax.Attributes.Add(targetTypeUri, value); } } }
/// <summary> /// Converts the Simple Registration extension response to whatever format the original /// attribute request extension came in. /// </summary> /// <param name="request">The authentication request with the response extensions already added.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns> /// A task that completes with the asynchronous operation. /// </returns> /// <remarks> /// If the original attribute request came in as AX, the Simple Registration extension is converted /// to an AX response and then the Simple Registration extension is removed from the response. /// </remarks> internal static async Task ConvertSregToMatchRequestAsync(this Provider.IHostProcessedRequest request, CancellationToken cancellationToken) { var req = (Provider.HostProcessedRequest)request; var protocolMessage = await req.GetResponseAsync(cancellationToken); var response = protocolMessage as IProtocolMessageWithExtensions; // negative responses don't support extensions. var sregRequest = request.GetExtension <ClaimsRequest>(); if (sregRequest != null && response != null) { if (sregRequest.Synthesized) { var axRequest = request.GetExtension <FetchRequest>(); ErrorUtilities.VerifyInternal(axRequest != null, "How do we have a synthesized Sreg request without an AX request?"); var sregResponse = response.Extensions.OfType <ClaimsResponse>().SingleOrDefault(); if (sregResponse == null) { // No Sreg response to copy from. return; } // Remove the sreg response since the RP didn't ask for it. response.Extensions.Remove(sregResponse); AXAttributeFormats format = OpenIdExtensionsInteropHelper.DetectAXFormat(axRequest.Attributes.Select(att => att.TypeUri)); if (format == AXAttributeFormats.None) { // No recognized AX attributes were requested. return; } var axResponse = response.Extensions.OfType <FetchResponse>().SingleOrDefault(); if (axResponse == null) { axResponse = new FetchResponse(); response.Extensions.Add(axResponse); } AddAXAttributeValue(axResponse, WellKnownAttributes.BirthDate.WholeBirthDate, format, sregResponse.BirthDateRaw); AddAXAttributeValue(axResponse, WellKnownAttributes.Contact.HomeAddress.Country, format, sregResponse.Country); AddAXAttributeValue(axResponse, WellKnownAttributes.Contact.HomeAddress.PostalCode, format, sregResponse.PostalCode); AddAXAttributeValue(axResponse, WellKnownAttributes.Contact.Email, format, sregResponse.Email); AddAXAttributeValue(axResponse, WellKnownAttributes.Name.FullName, format, sregResponse.FullName); AddAXAttributeValue(axResponse, WellKnownAttributes.Name.Alias, format, sregResponse.Nickname); AddAXAttributeValue(axResponse, WellKnownAttributes.Preferences.TimeZone, format, sregResponse.TimeZone); AddAXAttributeValue(axResponse, WellKnownAttributes.Preferences.Language, format, sregResponse.Language); if (sregResponse.Gender.HasValue) { AddAXAttributeValue(axResponse, WellKnownAttributes.Person.Gender, format, OpenIdExtensionsInteropHelper.GenderEncoder.Encode(sregResponse.Gender)); } } } }
public static void SpreadSregToAX(this RelyingParty.IAuthenticationRequest request, AXAttributeFormats attributeFormats) { Requires.NotNull(request, "request"); var req = (RelyingParty.AuthenticationRequest)request; var sreg = req.AppliedExtensions.OfType <ClaimsRequest>().SingleOrDefault(); if (sreg == null) { Logger.OpenId.Debug("No Simple Registration (ClaimsRequest) extension present in the request to spread to AX."); return; } if (req.DiscoveryResult.IsExtensionSupported <ClaimsRequest>()) { Logger.OpenId.Debug("Skipping generation of AX request because the Identifier advertises the Provider supports the Sreg extension."); return; } var ax = req.AppliedExtensions.OfType <FetchRequest>().SingleOrDefault(); if (ax == null) { ax = new FetchRequest(); req.AddExtension(ax); } // Try to use just one AX Type URI format if we can figure out which type the OP accepts. AXAttributeFormats detectedFormat; if (TryDetectOPAttributeFormat(request, out detectedFormat)) { Logger.OpenId.Debug("Detected OP support for AX but not for Sreg. Removing Sreg extension request and using AX instead."); attributeFormats = detectedFormat; req.Extensions.Remove(sreg); } else { Logger.OpenId.Debug("Could not determine whether OP supported Sreg or AX. Using both extensions."); } foreach (AXAttributeFormats format in OpenIdExtensionsInteropHelper.ForEachFormat(attributeFormats)) { OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.BirthDate.WholeBirthDate, sreg.BirthDate); OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.Contact.HomeAddress.Country, sreg.Country); OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.Contact.Email, sreg.Email); OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.Name.FullName, sreg.FullName); OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.Person.Gender, sreg.Gender); OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.Preferences.Language, sreg.Language); OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.Name.Alias, sreg.Nickname); OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.Contact.HomeAddress.PostalCode, sreg.PostalCode); OpenIdExtensionsInteropHelper.FetchAttribute(ax, format, WellKnownAttributes.Preferences.TimeZone, sreg.TimeZone); } }
/// <summary> /// Gets the demand level for an AX attribute. /// </summary> /// <param name="ax">The AX fetch request to search for the attribute.</param> /// <param name="typeUri">The type URI of the attribute in axschema.org format.</param> /// <returns>The demand level for the attribute.</returns> private static DemandLevel GetDemandLevelFor(FetchRequest ax, string typeUri) { Requires.NotNull(ax, "ax"); Requires.NotNullOrEmpty(typeUri, "typeUri"); foreach (AXAttributeFormats format in OpenIdExtensionsInteropHelper.ForEachFormat(AXAttributeFormats.All)) { string typeUriInFormat = OpenIdExtensionsInteropHelper.TransformAXFormat(typeUri, format); if (ax.Attributes.Contains(typeUriInFormat)) { return(ax.Attributes[typeUriInFormat].IsRequired ? DemandLevel.Require : DemandLevel.Request); } } return(DemandLevel.NoRequest); }
/// <summary> /// Transforms an AX attribute type URI from the axschema.org format into a given format. /// </summary> /// <param name="axSchemaOrgFormatTypeUri">The ax schema org format type URI.</param> /// <param name="targetFormat">The target format. Only one flag should be set.</param> /// <returns>The AX attribute type URI in the target format.</returns> internal static string TransformAXFormatTestHook(string axSchemaOrgFormatTypeUri, AXAttributeFormats targetFormat) { return(OpenIdExtensionsInteropHelper.TransformAXFormat(axSchemaOrgFormatTypeUri, targetFormat)); }
/// <summary> /// Tries to find the exact format of AX attribute Type URI supported by the Provider. /// </summary> /// <param name="request">The authentication request.</param> /// <param name="attributeFormat">The attribute formats the RP will try if this discovery fails.</param> /// <returns>The AX format(s) to use based on the Provider's advertised AX support.</returns> private static bool TryDetectOPAttributeFormat(RelyingParty.IAuthenticationRequest request, out AXAttributeFormats attributeFormat) { Requires.NotNull(request, "request"); attributeFormat = OpenIdExtensionsInteropHelper.DetectAXFormat(request.DiscoveryResult.Capabilities); return(attributeFormat != AXAttributeFormats.None); }
/// <summary> /// Gets the attribute value if available. /// </summary> /// <param name="fetchResponse">The AX fetch response extension to look for the attribute value.</param> /// <param name="typeUri">The type URI of the attribute, using the axschema.org format of <see cref="WellKnownAttributes"/>.</param> /// <param name="formats">The AX type URI formats to search.</param> /// <returns> /// The first value of the attribute, if available. /// </returns> internal static string GetAttributeValue(this FetchResponse fetchResponse, string typeUri, AXAttributeFormats formats) { return(OpenIdExtensionsInteropHelper.ForEachFormat(formats).Select(format => fetchResponse.GetAttributeValue(OpenIdExtensionsInteropHelper.TransformAXFormat(typeUri, format))).FirstOrDefault(s => s != null)); }