got the server lib
This commit is contained in:
parent
36002d8ef8
commit
8929cc9bfa
68 changed files with 104 additions and 4250 deletions
|
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"dotnet": {
|
"dotnet": {
|
||||||
"enabled": false
|
"enabled": true
|
||||||
},
|
},
|
||||||
"msbuild": {
|
"msbuild": {
|
||||||
"enabled": false
|
"enabled": false
|
||||||
},
|
},
|
||||||
"scriptcs": {
|
"scriptcs": {
|
||||||
"enabled": false
|
"enabled": true
|
||||||
},
|
},
|
||||||
"Dnx": {
|
"Dnx": {
|
||||||
"enabled": true,
|
"enabled": false,
|
||||||
"enablePackageRestore": false,
|
"enablePackageRestore": false,
|
||||||
"projects": "src/*/project.json;*/project.json;project.json;test/*/project.json"
|
"projects": "src/*/project.json;*/project.json;project.json;test/*/project.json"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,208 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using GoogleTranslateNET.Misc;
|
|
||||||
using GoogleTranslateNET.Objects.Error;
|
|
||||||
using GoogleTranslateNET.Objects.LanguageDetection;
|
|
||||||
using GoogleTranslateNET.Objects.SupportedLanguages;
|
|
||||||
using GoogleTranslateNET.Objects.Translation;
|
|
||||||
using RestSharp;
|
|
||||||
using RestSharp.Deserializers;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
|
|
||||||
namespace GoogleTranslateNET
|
|
||||||
{
|
|
||||||
public class NoSevrerSideImplementationAttribute : Attribute
|
|
||||||
{
|
|
||||||
public string Reason { get ; private set; }
|
|
||||||
public NoSevrerSideImplementationAttribute(string reason) : base()
|
|
||||||
{
|
|
||||||
Reason = reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[NoSevrerSideImplementation("none")]
|
|
||||||
public class GoogleTranslate
|
|
||||||
{
|
|
||||||
private string _key;
|
|
||||||
private static RestClient _client = new RestClient("https://www.googleapis.com/language/translate/v2");
|
|
||||||
|
|
||||||
public GoogleTranslate(string key)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(key))
|
|
||||||
throw new ArgumentException("Key is required.", "key");
|
|
||||||
|
|
||||||
_key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// When true, the output from google is in human readable format.
|
|
||||||
/// Default: Not set, Google defaults to true
|
|
||||||
/// </summary>
|
|
||||||
public bool? PrettyPrint { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// When true, queries will be sent using HTTP POST instead of GET.
|
|
||||||
/// GET queries have a limit of 2000 characters, POST queries have a limit of 5000 characters.
|
|
||||||
/// Default: Not set, Google defaults to false
|
|
||||||
/// </summary>
|
|
||||||
public bool? LargeQuery { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Translates a text from one language to another.
|
|
||||||
/// You can input multiple texts and get them translated all at once.
|
|
||||||
/// Warning: Setting source and destination languages to the same language will result in an error.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sourceLanguage">The language to translate from. Set it to Language.Automatic to let Google Translate determine the language.</param>
|
|
||||||
/// <param name="destinationLanaguage">The language to translate to.</param>
|
|
||||||
/// <param name="text">The text to translate. You may input more than one text.</param>
|
|
||||||
/// <returns>The translated text.</returns>
|
|
||||||
public List<Translation> Translate(Language sourceLanguage, Language destinationLanaguage, params string[] text)
|
|
||||||
{
|
|
||||||
//https://www.googleapis.com/language/translate/v2?key=key&q=hello%20world&source=en&target=de
|
|
||||||
RestRequest request = CreateRequest(string.Empty);
|
|
||||||
|
|
||||||
CheckRequest(text);
|
|
||||||
|
|
||||||
//Required
|
|
||||||
foreach (string q in text)
|
|
||||||
{
|
|
||||||
request.AddParameter("q", q);
|
|
||||||
}
|
|
||||||
request.AddParameter("target", destinationLanaguage.GetStringValue());
|
|
||||||
|
|
||||||
//Optional
|
|
||||||
if (sourceLanguage != Language.Automatic)
|
|
||||||
request.AddParameter("source", sourceLanguage.GetStringValue());
|
|
||||||
|
|
||||||
//Output
|
|
||||||
TranslateResult results = GetResponse<TranslateResult>(request);
|
|
||||||
return results.Data.Translations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gives you a list of supported languages.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetLanguage">When defined, gives you a list of languages that translates into the target language.</param>
|
|
||||||
/// <returns>A list of supported languages</returns>
|
|
||||||
public List<TranslationLanaguage> GetSupportedLanguages(Language targetLanguage = Language.Unknown)
|
|
||||||
{
|
|
||||||
//https://www.googleapis.com/language/translate/v2/languages?key=key&target=zh-TW
|
|
||||||
RestRequest request = CreateRequest("languages");
|
|
||||||
|
|
||||||
//Optional
|
|
||||||
if (targetLanguage != Language.Unknown)
|
|
||||||
request.AddParameter("target", targetLanguage.GetStringValue());
|
|
||||||
|
|
||||||
//Output
|
|
||||||
SupportedLanguageResult results = GetResponse<SupportedLanguageResult>(request);
|
|
||||||
return results.Data.Languages;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Detects the languages that might be used in the text.
|
|
||||||
/// You can send more than one text in a single request to detect multiple texts.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">The text to use when detecting languages.</param>
|
|
||||||
/// <returns>A list of languages that might be used in the text.</returns>
|
|
||||||
public List<LanguageDetection> DetectLanguage(params string[] text)
|
|
||||||
{
|
|
||||||
//https://www.googleapis.com/language/translate/v2/detect?key=key&q=google+translate+is+fast
|
|
||||||
RestRequest request = CreateRequest("detect");
|
|
||||||
|
|
||||||
CheckRequest(text);
|
|
||||||
|
|
||||||
//Required
|
|
||||||
foreach (string q in text)
|
|
||||||
{
|
|
||||||
request.AddParameter("q", q);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Output
|
|
||||||
LanguageDetectionResult results = GetResponse<LanguageDetectionResult>(request);
|
|
||||||
|
|
||||||
//Flatten the results from Google Translate API
|
|
||||||
List<LanguageDetection> detections = new List<LanguageDetection>();
|
|
||||||
foreach (List<LanguageDetection> languageDetections in results.Data.Detections)
|
|
||||||
{
|
|
||||||
detections.AddRange(languageDetections);
|
|
||||||
}
|
|
||||||
|
|
||||||
return detections;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckRequest(IEnumerable<string> requestContent)
|
|
||||||
{
|
|
||||||
//Compute the total size of the content
|
|
||||||
int sum = requestContent.Sum(item => item.Length);
|
|
||||||
|
|
||||||
if (((LargeQuery.HasValue && !LargeQuery.Value) || !LargeQuery.HasValue) && sum >= 2000)
|
|
||||||
{
|
|
||||||
throw new ArgumentException("Your text content is larger than 2000 characters. Set LargeQuery to 'true' to enable support up to 5000 characters.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sum > 5000)
|
|
||||||
throw new ArgumentException("Your text content is larger than 5000 characters. Google Translate only allow up to 5000 characters");
|
|
||||||
}
|
|
||||||
|
|
||||||
private RestRequest CreateRequest(string function)
|
|
||||||
{
|
|
||||||
RestRequest request;
|
|
||||||
|
|
||||||
if (LargeQuery.HasValue && LargeQuery.Value)
|
|
||||||
{
|
|
||||||
request = new RestRequest(function, Method.POST);
|
|
||||||
|
|
||||||
//To use POST, you must use the X-HTTP-Method-Override header to tell the Translate API to treat the request as a GET (use X-HTTP-Method-Override: GET).
|
|
||||||
request.AddHeader("X-HTTP-Method-Override", "GET");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
request = new RestRequest(function, Method.GET);
|
|
||||||
}
|
|
||||||
|
|
||||||
request.AddParameter("key", _key);
|
|
||||||
|
|
||||||
if (PrettyPrint.HasValue)
|
|
||||||
request.AddParameter("prettyprint", PrettyPrint.ToString().ToLower());
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private T GetResponse<T>(RestRequest request)
|
|
||||||
{
|
|
||||||
RestResponse response = (RestResponse)_client.Execute(request);
|
|
||||||
JsonDeserializer deserializer = new JsonDeserializer();
|
|
||||||
T results = deserializer.Deserialize<T>(response);
|
|
||||||
|
|
||||||
//Try to deserialize it as an error - it is a hack since I'm using generics here.
|
|
||||||
ErrorResponse errorResponse = deserializer.Deserialize<ErrorResponse>(response);
|
|
||||||
|
|
||||||
if (errorResponse.Error != null)
|
|
||||||
throw new Exception(GetErrorText(errorResponse.Error));
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetErrorText(Error error)
|
|
||||||
{
|
|
||||||
if (error != null)
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.Append(error.Message);
|
|
||||||
|
|
||||||
if (error.Errors.Count >= 1)
|
|
||||||
{
|
|
||||||
ErrorData errorData = error.Errors.First();
|
|
||||||
sb.Append("Reason: " + errorData.Reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return "There was an error. Unable to determine the cause.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
using GoogleTranslateNET.Misc;
|
|
||||||
|
|
||||||
namespace GoogleTranslateNET
|
|
||||||
{
|
|
||||||
public enum Language
|
|
||||||
{
|
|
||||||
Unknown,
|
|
||||||
Automatic,
|
|
||||||
[StringValue("af")]
|
|
||||||
Afrikaans,
|
|
||||||
[StringValue("sq")]
|
|
||||||
Albanian,
|
|
||||||
[StringValue("ar")]
|
|
||||||
Arabic,
|
|
||||||
[StringValue("be")]
|
|
||||||
Belarusian,
|
|
||||||
[StringValue("bg")]
|
|
||||||
Bulgarian,
|
|
||||||
[StringValue("ca")]
|
|
||||||
Catalan,
|
|
||||||
[StringValue("zh")]
|
|
||||||
ChineseSimplified,
|
|
||||||
[StringValue("zh-TW")]
|
|
||||||
ChineseTraditional,
|
|
||||||
[StringValue("hr")]
|
|
||||||
Croatian,
|
|
||||||
[StringValue("cs")]
|
|
||||||
Czech,
|
|
||||||
[StringValue("da")]
|
|
||||||
Danish,
|
|
||||||
[StringValue("nl")]
|
|
||||||
Dutch,
|
|
||||||
[StringValue("en")]
|
|
||||||
English,
|
|
||||||
[StringValue("eo")]
|
|
||||||
Esperanto,
|
|
||||||
[StringValue("et")]
|
|
||||||
Estonian,
|
|
||||||
[StringValue("tl")]
|
|
||||||
Filipino,
|
|
||||||
[StringValue("fi")]
|
|
||||||
Finnish,
|
|
||||||
[StringValue("fr")]
|
|
||||||
French,
|
|
||||||
[StringValue("gl")]
|
|
||||||
Galician,
|
|
||||||
[StringValue("de")]
|
|
||||||
German,
|
|
||||||
[StringValue("el")]
|
|
||||||
Greek,
|
|
||||||
[StringValue("ht")]
|
|
||||||
HaitianCreole,
|
|
||||||
[StringValue("iw")]
|
|
||||||
Hebrew,
|
|
||||||
[StringValue("hi")]
|
|
||||||
Hindi,
|
|
||||||
[StringValue("hu")]
|
|
||||||
Hungarian,
|
|
||||||
[StringValue("is")]
|
|
||||||
Icelandic,
|
|
||||||
[StringValue("id")]
|
|
||||||
Indonesian,
|
|
||||||
[StringValue("ga")]
|
|
||||||
Irish,
|
|
||||||
[StringValue("it")]
|
|
||||||
Italian,
|
|
||||||
[StringValue("ja")]
|
|
||||||
Japanese,
|
|
||||||
[StringValue("ko")]
|
|
||||||
Korean,
|
|
||||||
[StringValue("lv")]
|
|
||||||
Latvian,
|
|
||||||
[StringValue("lt")]
|
|
||||||
Lithuanian,
|
|
||||||
[StringValue("mk")]
|
|
||||||
Macedonian,
|
|
||||||
[StringValue("ms")]
|
|
||||||
Malay,
|
|
||||||
[StringValue("mt")]
|
|
||||||
Maltese,
|
|
||||||
[StringValue("no")]
|
|
||||||
Norwegian,
|
|
||||||
[StringValue("fa")]
|
|
||||||
Persian,
|
|
||||||
[StringValue("pl")]
|
|
||||||
Polish,
|
|
||||||
[StringValue("pt")]
|
|
||||||
Portuguese,
|
|
||||||
[StringValue("ro")]
|
|
||||||
Romanian,
|
|
||||||
[StringValue("ru")]
|
|
||||||
Russian,
|
|
||||||
[StringValue("sr")]
|
|
||||||
Serbian,
|
|
||||||
[StringValue("sk")]
|
|
||||||
Slovak,
|
|
||||||
[StringValue("sl")]
|
|
||||||
Slovenian,
|
|
||||||
[StringValue("es")]
|
|
||||||
Spanish,
|
|
||||||
[StringValue("sw")]
|
|
||||||
Swahili,
|
|
||||||
[StringValue("sv")]
|
|
||||||
Swedish,
|
|
||||||
[StringValue("th")]
|
|
||||||
Thai,
|
|
||||||
[StringValue("tr")]
|
|
||||||
Turkish,
|
|
||||||
[StringValue("uk")]
|
|
||||||
Ukrainian,
|
|
||||||
[StringValue("vi")]
|
|
||||||
Vietnamese,
|
|
||||||
[StringValue("cy")]
|
|
||||||
Welsh,
|
|
||||||
[StringValue("yi")]
|
|
||||||
Yiddish
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace GoogleTranslateNET.Misc
|
|
||||||
{
|
|
||||||
public static class ExtensionMethods
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Will get the string value for a given enums value, this will
|
|
||||||
/// only work if you assign the StringValue attribute to
|
|
||||||
/// the items in your enum.
|
|
||||||
/// Source: http://weblogs.asp.net/stefansedich/archive/2008/03/12/enum-with-string-values-in-c.aspx
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string GetStringValue(this Enum value)
|
|
||||||
{
|
|
||||||
// Get the type
|
|
||||||
Type type = value.GetType();
|
|
||||||
|
|
||||||
// Get fieldinfo for this type
|
|
||||||
FieldInfo fieldInfo = type.GetField(value.ToString());
|
|
||||||
|
|
||||||
// Get the stringvalue attributes
|
|
||||||
StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes(
|
|
||||||
typeof(StringValueAttribute), false) as StringValueAttribute[];
|
|
||||||
|
|
||||||
// Return the first if there was a match.
|
|
||||||
return attribs.Length > 0 ? attribs[0].StringValue : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace GoogleTranslateNET.Misc
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This attribute is used to represent a string value
|
|
||||||
/// for a value in an enum.
|
|
||||||
/// </summary>
|
|
||||||
public class StringValueAttribute : Attribute
|
|
||||||
{
|
|
||||||
public string StringValue { get; private set; }
|
|
||||||
|
|
||||||
public StringValueAttribute(string value)
|
|
||||||
{
|
|
||||||
StringValue = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace GoogleTranslateNET.Objects.Error
|
|
||||||
{
|
|
||||||
public class Error
|
|
||||||
{
|
|
||||||
public int Code { get; set; }
|
|
||||||
public string Message { get; set; }
|
|
||||||
public List<ErrorData> Errors { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
namespace GoogleTranslateNET.Objects.Error
|
|
||||||
{
|
|
||||||
public class ErrorData
|
|
||||||
{
|
|
||||||
public string Domain { get; set; }
|
|
||||||
public string Reason { get; set; }
|
|
||||||
public string Message { get; set; }
|
|
||||||
public string LocationType { get; set; }
|
|
||||||
public string Location { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
namespace GoogleTranslateNET.Objects.Error
|
|
||||||
{
|
|
||||||
public class ErrorResponse
|
|
||||||
{
|
|
||||||
public Error Error { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
namespace GoogleTranslateNET.Objects.LanguageDetection
|
|
||||||
{
|
|
||||||
public class LanguageDetection
|
|
||||||
{
|
|
||||||
public string Language { get; set; }
|
|
||||||
public bool IsReliable { get; set; }
|
|
||||||
public float Confidence { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace GoogleTranslateNET.Objects.LanguageDetection
|
|
||||||
{
|
|
||||||
public class LanguageDetectionData
|
|
||||||
{
|
|
||||||
public List<List<LanguageDetection>> Detections { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
namespace GoogleTranslateNET.Objects.LanguageDetection
|
|
||||||
{
|
|
||||||
public class LanguageDetectionResult
|
|
||||||
{
|
|
||||||
public LanguageDetectionData Data { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace GoogleTranslateNET.Objects.SupportedLanguages
|
|
||||||
{
|
|
||||||
public class SupportedLanguageData
|
|
||||||
{
|
|
||||||
public List<TranslationLanaguage> Languages { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
namespace GoogleTranslateNET.Objects.SupportedLanguages
|
|
||||||
{
|
|
||||||
public class SupportedLanguageResult
|
|
||||||
{
|
|
||||||
public SupportedLanguageData Data { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
namespace GoogleTranslateNET.Objects.SupportedLanguages
|
|
||||||
{
|
|
||||||
public class TranslationLanaguage
|
|
||||||
{
|
|
||||||
public string Language { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
namespace GoogleTranslateNET.Objects.Translation
|
|
||||||
{
|
|
||||||
public class TranslateResult
|
|
||||||
{
|
|
||||||
public TranslationData Data { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
namespace GoogleTranslateNET.Objects.Translation
|
|
||||||
{
|
|
||||||
public class Translation
|
|
||||||
{
|
|
||||||
public string TranslatedText { get; set; }
|
|
||||||
public string DetectedSourceLanguage { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace GoogleTranslateNET.Objects.Translation
|
|
||||||
{
|
|
||||||
public class TranslationData
|
|
||||||
{
|
|
||||||
public List<Translation> Translations { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
{
|
|
||||||
"version": "1.0.5-*",
|
|
||||||
"title": "Yavsc Google Translate [DNX]",
|
|
||||||
"description": "Google Translate for DNX",
|
|
||||||
"authors": [
|
|
||||||
"Paul Schneider <paul@pschneider.fr>"
|
|
||||||
],
|
|
||||||
"packOptions": {
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/pazof/yavsc"
|
|
||||||
},
|
|
||||||
"licenseUrl": "https://github.com/pazof/yavsc/blob/vnext/LICENSE",
|
|
||||||
"requireLicenseAcceptance": true,
|
|
||||||
"owners": [
|
|
||||||
"Paul Schneider <paul@pschneider.fr>"
|
|
||||||
],
|
|
||||||
"summary": "CSharp Google Tranlate API",
|
|
||||||
"projectUrl": "http://yavsc.pschneider.fr",
|
|
||||||
"tags": [
|
|
||||||
"Translation"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tooling": {
|
|
||||||
"defaultNamespace": "Yavsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"Newtonsoft.Json": "6.0.1-beta1",
|
|
||||||
"Gapi.net45": "1.0.1",
|
|
||||||
"RestSharp": "103.4.0"
|
|
||||||
},
|
|
||||||
"frameworks": {
|
|
||||||
"dnx451": {
|
|
||||||
"frameworkAssemblies": {
|
|
||||||
"System.ComponentModel.DataAnnotations": "4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"net46": {
|
|
||||||
"frameworkAssemblies": {
|
|
||||||
"System.ComponentModel.DataAnnotations": "4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"net461": {
|
|
||||||
"frameworkAssemblies": {
|
|
||||||
"System.ComponentModel.DataAnnotations": "4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"net452": {
|
|
||||||
"frameworkAssemblies": {
|
|
||||||
"System.ComponentModel.DataAnnotations": "4.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"net451": {
|
|
||||||
"frameworkAssemblies": {
|
|
||||||
"System.ComponentModel.DataAnnotations": "4.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
using Microsoft.AspNet.Http.Authentication;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Exposes the security.Challenge environment value as a strong type.
|
|
||||||
/// </summary>
|
|
||||||
public class AuthenticationResponseChallenge
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AuthenticationResponseChallenge"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="authenticationTypes"></param>
|
|
||||||
/// <param name="properties"></param>
|
|
||||||
public AuthenticationResponseChallenge(string[] authenticationTypes, AuthenticationProperties properties)
|
|
||||||
{
|
|
||||||
AuthenticationTypes = authenticationTypes;
|
|
||||||
Properties = properties ?? new AuthenticationProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of the authentication types that should send a challenge in the response.
|
|
||||||
/// </summary>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "By design")]
|
|
||||||
public string[] AuthenticationTypes { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary used to store state values about the authentication session.
|
|
||||||
/// </summary>
|
|
||||||
public AuthenticationProperties Properties { get; private set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
using Microsoft.AspNet.Http.Authentication;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Exposes the security.SignIn environment value as a strong type.
|
|
||||||
/// </summary>
|
|
||||||
public class AuthenticationResponseGrant
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AuthenticationResponseGrant"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="identity"></param>
|
|
||||||
/// <param name="properties"></param>
|
|
||||||
public AuthenticationResponseGrant(ClaimsIdentity identity, AuthenticationProperties properties)
|
|
||||||
{
|
|
||||||
Principal = new ClaimsPrincipal(identity);
|
|
||||||
Identity = identity;
|
|
||||||
Properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="AuthenticationResponseGrant"/> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="principal"></param>
|
|
||||||
/// <param name="properties"></param>
|
|
||||||
public AuthenticationResponseGrant(ClaimsPrincipal principal, AuthenticationProperties properties)
|
|
||||||
{
|
|
||||||
if (principal == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("principal");
|
|
||||||
}
|
|
||||||
|
|
||||||
Principal = principal;
|
|
||||||
Identity = principal.Identities.FirstOrDefault();
|
|
||||||
Properties = properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The identity associated with the user sign in.
|
|
||||||
/// </summary>
|
|
||||||
public ClaimsIdentity Identity { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The security principal associated with the user sign in.
|
|
||||||
/// </summary>
|
|
||||||
public ClaimsPrincipal Principal { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary used to store state values about the authentication session.
|
|
||||||
/// </summary>
|
|
||||||
public AuthenticationProperties Properties { get; private set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
public class AuthenticationTokenCreateContext : BaseContext
|
|
||||||
{
|
|
||||||
private readonly ISecureDataFormat<AuthenticationTicket> _secureDataFormat;
|
|
||||||
|
|
||||||
public AuthenticationTokenCreateContext(HttpContext context, ISecureDataFormat<AuthenticationTicket> secureDataFormat, AuthenticationTicket ticket) : base(context)
|
|
||||||
{
|
|
||||||
if (secureDataFormat == null)
|
|
||||||
throw new ArgumentNullException(nameof(secureDataFormat));
|
|
||||||
|
|
||||||
if (ticket == null)
|
|
||||||
throw new ArgumentNullException(nameof(ticket));
|
|
||||||
|
|
||||||
_secureDataFormat = secureDataFormat;
|
|
||||||
|
|
||||||
Ticket = ticket;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Token { get; protected set; }
|
|
||||||
|
|
||||||
public AuthenticationTicket Ticket { get; protected set; }
|
|
||||||
|
|
||||||
public string SerializeTicket()
|
|
||||||
{
|
|
||||||
return _secureDataFormat.Protect(Ticket);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetToken(string tokenValue)
|
|
||||||
{
|
|
||||||
if (tokenValue == null)
|
|
||||||
throw new ArgumentNullException(nameof(tokenValue));
|
|
||||||
|
|
||||||
Token = tokenValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
public class AuthenticationTokenProvider : IAuthenticationTokenProvider
|
|
||||||
{
|
|
||||||
public Action<AuthenticationTokenCreateContext> OnCreate { get; set; }
|
|
||||||
public Func<AuthenticationTokenCreateContext, Task> OnCreateAsync { get; set; }
|
|
||||||
public Action<AuthenticationTokenReceiveContext> OnReceive { get; set; }
|
|
||||||
public Func<AuthenticationTokenReceiveContext, Task> OnReceiveAsync { get; set; }
|
|
||||||
|
|
||||||
public virtual void Create(AuthenticationTokenCreateContext context)
|
|
||||||
{
|
|
||||||
if (OnCreateAsync != null && OnCreate == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Authentication token did not provide an OnCreate method.");
|
|
||||||
}
|
|
||||||
if (OnCreate != null)
|
|
||||||
{
|
|
||||||
OnCreate.Invoke(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual async Task CreateAsync(AuthenticationTokenCreateContext context)
|
|
||||||
{
|
|
||||||
if (OnCreateAsync != null && OnCreate == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Authentication token did not provide an OnCreate method.");
|
|
||||||
}
|
|
||||||
if (OnCreateAsync != null)
|
|
||||||
{
|
|
||||||
await OnCreateAsync.Invoke(context);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Create(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Receive(AuthenticationTokenReceiveContext context)
|
|
||||||
{
|
|
||||||
if (OnReceiveAsync != null && OnReceive == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Authentication token did not provide an OnReceive method.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OnReceive != null)
|
|
||||||
{
|
|
||||||
OnReceive.Invoke(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
|
|
||||||
{
|
|
||||||
if (OnReceiveAsync != null && OnReceive == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Authentication token did not provide an OnReceive method.");
|
|
||||||
}
|
|
||||||
if (OnReceiveAsync != null)
|
|
||||||
{
|
|
||||||
await OnReceiveAsync.Invoke(context);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Receive(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
public class AuthenticationTokenReceiveContext : BaseContext
|
|
||||||
{
|
|
||||||
private readonly ISecureDataFormat<AuthenticationTicket> _secureDataFormat;
|
|
||||||
|
|
||||||
public AuthenticationTokenReceiveContext(HttpContext context, ISecureDataFormat<AuthenticationTicket> secureDataFormat, string token) : base(context)
|
|
||||||
{
|
|
||||||
if (secureDataFormat == null)
|
|
||||||
throw new ArgumentNullException(nameof(secureDataFormat));
|
|
||||||
|
|
||||||
if (token == null)
|
|
||||||
throw new ArgumentNullException(nameof(token));
|
|
||||||
|
|
||||||
_secureDataFormat = secureDataFormat;
|
|
||||||
|
|
||||||
Token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Token { get; protected set; }
|
|
||||||
|
|
||||||
public AuthenticationTicket Ticket { get; protected set; }
|
|
||||||
|
|
||||||
public void DeserializeTicket(string protectedData)
|
|
||||||
{
|
|
||||||
Ticket = _secureDataFormat.Unprotect(protectedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetTicket(AuthenticationTicket ticket)
|
|
||||||
{
|
|
||||||
if (ticket == null)
|
|
||||||
throw new ArgumentNullException(nameof(ticket));
|
|
||||||
|
|
||||||
Ticket = ticket;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,138 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object representing the information contained in the query string of an Authorize endpoint request.
|
|
||||||
/// </summary>
|
|
||||||
public class AuthorizeEndpointRequest
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance populated with values from the query string parameters.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="parameters">Query string parameters from a request.</param>
|
|
||||||
public AuthorizeEndpointRequest(IReadableStringCollection parameters)
|
|
||||||
{
|
|
||||||
if (parameters == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("parameters");
|
|
||||||
}
|
|
||||||
|
|
||||||
Scope = new List<string>();
|
|
||||||
|
|
||||||
foreach (var parameter in parameters)
|
|
||||||
{
|
|
||||||
AddParameter(parameter.Key, parameters[parameter.Key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "response_type" query string parameter of the Authorize request. Known values are "code" and "token".
|
|
||||||
/// </summary>
|
|
||||||
public string ResponseType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "response_mode" query string parameter of the Authorize request. Known values are "query", "fragment" and "form_post"
|
|
||||||
/// See also, http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
|
|
||||||
/// </summary>
|
|
||||||
public string ResponseMode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "client_id" query string parameter of the Authorize request.
|
|
||||||
/// </summary>
|
|
||||||
public string ClientId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "redirect_uri" query string parameter of the Authorize request. May be absent if the server should use the
|
|
||||||
/// redirect uri known to be registered to the client id.
|
|
||||||
/// </summary>
|
|
||||||
[SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "By design")]
|
|
||||||
public string RedirectUri { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "scope" query string parameter of the Authorize request. May be absent if the server should use default scopes.
|
|
||||||
/// </summary>
|
|
||||||
public IList<string> Scope { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "scope" query string parameter of the Authorize request. May be absent if the client does not require state to be
|
|
||||||
/// included when returning to the RedirectUri.
|
|
||||||
/// </summary>
|
|
||||||
public string State { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if the "response_type" query string parameter is "code".
|
|
||||||
/// See also, http://tools.ietf.org/html/rfc6749#section-4.1.1
|
|
||||||
/// </summary>
|
|
||||||
public bool IsAuthorizationCodeGrantType
|
|
||||||
{
|
|
||||||
get { return ContainsGrantType(Constants.ResponseTypes.Code); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if the "response_type" query string parameter is "token".
|
|
||||||
/// See also, http://tools.ietf.org/html/rfc6749#section-4.2.1
|
|
||||||
/// </summary>
|
|
||||||
public bool IsImplicitGrantType
|
|
||||||
{
|
|
||||||
get { return ContainsGrantType(Constants.ResponseTypes.Token); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsFormPostResponseMode
|
|
||||||
{
|
|
||||||
get { return string.Equals(ResponseMode, Constants.ResponseModes.FormPost, StringComparison.Ordinal); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if the "response_type" query string contains the passed responseType.
|
|
||||||
/// See also, http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="responseType">The responseType that is expected within the "response_type" query string</param>
|
|
||||||
/// <returns>True if the "response_type" query string contains the passed responseType.</returns>
|
|
||||||
public bool ContainsGrantType(string responseType)
|
|
||||||
{
|
|
||||||
var parts = ResponseType.Split(' ');
|
|
||||||
foreach (var part in parts)
|
|
||||||
{
|
|
||||||
if (string.Equals(part, responseType, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddParameter(string name, string value)
|
|
||||||
{
|
|
||||||
if (string.Equals(name, Constants.Parameters.ResponseType, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
ResponseType = value;
|
|
||||||
}
|
|
||||||
else if (string.Equals(name, Constants.Parameters.ClientId, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
ClientId = value;
|
|
||||||
}
|
|
||||||
else if (string.Equals(name, Constants.Parameters.RedirectUri, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
RedirectUri = value;
|
|
||||||
}
|
|
||||||
else if (string.Equals(name, Constants.Parameters.Scope, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
Scope = value.Split(' ');
|
|
||||||
}
|
|
||||||
else if (string.Equals(name, Constants.Parameters.State, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
State = value;
|
|
||||||
}
|
|
||||||
else if (string.Equals(name, Constants.Parameters.ResponseMode, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
ResponseMode = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class for OAuth server endpoint contexts
|
|
||||||
/// </summary>
|
|
||||||
public class BaseOAuthEndpointContext : BaseContext
|
|
||||||
{
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of <see cref="BaseOAuthEndpointContext"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The <see cref="HttpContext"/> to use for this endpoint context.</param>
|
|
||||||
/// <param name="options">The <see cref="OAuthAuthorizationServerOptions"/> to use for this endpoint context.</param>
|
|
||||||
public BaseOAuthEndpointContext(HttpContext context, OAuthAuthorizationServerOptions options) : base(context)
|
|
||||||
{
|
|
||||||
if (options == null)
|
|
||||||
throw new ArgumentNullException(nameof(options));
|
|
||||||
|
|
||||||
Options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Members
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the OAuth server options.
|
|
||||||
/// </summary>
|
|
||||||
public OAuthAuthorizationServerOptions Options { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class used for certain event contexts
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseValidatingClientContext : BaseValidatingContext<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes base class used for certain event contexts
|
|
||||||
/// </summary>
|
|
||||||
protected BaseValidatingClientContext(HttpContext context, OAuthAuthorizationServerOptions options, string clientId) : base(context, options)
|
|
||||||
{
|
|
||||||
ClientId = clientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "client_id" parameter for the current request. The Authorization Server application is responsible for
|
|
||||||
/// validating this value identifies a registered client.
|
|
||||||
/// </summary>
|
|
||||||
public string ClientId { get; protected set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class used for certain event contexts
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseValidatingContext<TOptions> : BaseContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes base class used for certain event contexts
|
|
||||||
/// </summary>
|
|
||||||
protected BaseValidatingContext(HttpContext context, TOptions options) : base(context)
|
|
||||||
{
|
|
||||||
Options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The context options.
|
|
||||||
/// </summary>
|
|
||||||
public TOptions Options { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if application code has called any of the Validate methods on this context.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsValidated { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True if application code has called any of the SetError methods on this context.
|
|
||||||
/// </summary>
|
|
||||||
public bool HasError { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The error argument provided when SetError was called on this context. This is eventually
|
|
||||||
/// returned to the client app as the OAuth "error" parameter.
|
|
||||||
/// </summary>
|
|
||||||
public string Error { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The optional errorDescription argument provided when SetError was called on this context. This is eventually
|
|
||||||
/// returned to the client app as the OAuth "error_description" parameter.
|
|
||||||
/// </summary>
|
|
||||||
public string ErrorDescription { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The optional errorUri argument provided when SetError was called on this context. This is eventually
|
|
||||||
/// returned to the client app as the OAuth "error_uri" parameter.
|
|
||||||
/// </summary>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "error_uri is a string value in the protocol")]
|
|
||||||
public string ErrorUri { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marks this context as validated by the application. IsValidated becomes true and HasError becomes false as a result of calling.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>True if the validation has taken effect.</returns>
|
|
||||||
public virtual bool Validated()
|
|
||||||
{
|
|
||||||
IsValidated = true;
|
|
||||||
HasError = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marks this context as not validated by the application. IsValidated and HasError become false as a result of calling.
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Rejected()
|
|
||||||
{
|
|
||||||
IsValidated = false;
|
|
||||||
HasError = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marks this context as not validated by the application and assigns various error information properties.
|
|
||||||
/// HasError becomes true and IsValidated becomes false as a result of calling.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="error">Assigned to the Error property</param>
|
|
||||||
public void SetError(string error)
|
|
||||||
{
|
|
||||||
SetError(error, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marks this context as not validated by the application and assigns various error information properties.
|
|
||||||
/// HasError becomes true and IsValidated becomes false as a result of calling.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="error">Assigned to the Error property</param>
|
|
||||||
/// <param name="errorDescription">Assigned to the ErrorDescription property</param>
|
|
||||||
public void SetError(string error, string errorDescription)
|
|
||||||
{
|
|
||||||
SetError(error, errorDescription, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marks this context as not validated by the application and assigns various error information properties.
|
|
||||||
/// HasError becomes true and IsValidated becomes false as a result of calling.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="error">Assigned to the Error property</param>
|
|
||||||
/// <param name="errorDescription">Assigned to the ErrorDescription property</param>
|
|
||||||
/// <param name="errorUri">Assigned to the ErrorUri property</param>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "2#", Justification = "error_uri is a string value in the protocol")]
|
|
||||||
public void SetError(string error, string errorDescription, string errorUri)
|
|
||||||
{
|
|
||||||
Error = error;
|
|
||||||
ErrorDescription = errorDescription;
|
|
||||||
ErrorUri = errorUri;
|
|
||||||
Rejected();
|
|
||||||
HasError = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Microsoft.AspNet.Http.Authentication;
|
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class used for certain event contexts
|
|
||||||
/// </summary>
|
|
||||||
public abstract class BaseValidatingTicketContext<TOptions> : BaseValidatingContext<TOptions> where TOptions : AuthenticationOptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes base class used for certain event contexts
|
|
||||||
/// </summary>
|
|
||||||
protected BaseValidatingTicketContext(HttpContext context, TOptions options, AuthenticationTicket ticket) : base(context, options)
|
|
||||||
{
|
|
||||||
Ticket = ticket;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains the identity and properties for the application to authenticate. If the Validated method
|
|
||||||
/// is invoked with an AuthenticationTicket or ClaimsIdentity argument, that new value is assigned to
|
|
||||||
/// this property in addition to changing IsValidated to true.
|
|
||||||
/// </summary>
|
|
||||||
public AuthenticationTicket Ticket { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Replaces the ticket information on this context and marks it as as validated by the application.
|
|
||||||
/// IsValidated becomes true and HasError becomes false as a result of calling.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="ticket">Assigned to the Ticket property</param>
|
|
||||||
/// <returns>True if the validation has taken effect.</returns>
|
|
||||||
public bool Validated(AuthenticationTicket ticket)
|
|
||||||
{
|
|
||||||
Ticket = ticket;
|
|
||||||
return Validated();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Alters the ticket information on this context and marks it as as validated by the application.
|
|
||||||
/// IsValidated becomes true and HasError becomes false as a result of calling.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="principal">Assigned to the Ticket.Identity property</param>
|
|
||||||
/// <returns>True if the validation has taken effect.</returns>
|
|
||||||
public bool Validated(ClaimsPrincipal principal)
|
|
||||||
{
|
|
||||||
AuthenticationProperties properties = Ticket != null ? Ticket.Properties : new AuthenticationProperties();
|
|
||||||
return Validated(new AuthenticationTicket(principal, properties, Options.AuthenticationScheme));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
internal static class DefaultBehavior
|
|
||||||
{
|
|
||||||
internal static readonly Func<OAuthValidateAuthorizeRequestContext, Task> ValidateAuthorizeRequest = context =>
|
|
||||||
{
|
|
||||||
context.Validated();
|
|
||||||
return Task.FromResult<object>(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly Func<OAuthValidateTokenRequestContext, Task> ValidateTokenRequest = context =>
|
|
||||||
{
|
|
||||||
context.Validated();
|
|
||||||
return Task.FromResult<object>(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly Func<OAuthGrantAuthorizationCodeContext, Task> GrantAuthorizationCode = context =>
|
|
||||||
{
|
|
||||||
if (context.Ticket != null && context.Ticket.Principal != null && context.Ticket.Principal.Identity.IsAuthenticated)
|
|
||||||
{
|
|
||||||
context.Validated();
|
|
||||||
}
|
|
||||||
return Task.FromResult<object>(null);
|
|
||||||
};
|
|
||||||
|
|
||||||
internal static readonly Func<OAuthGrantRefreshTokenContext, Task> GrantRefreshToken = context =>
|
|
||||||
{
|
|
||||||
if (context.Ticket != null && context.Ticket.Principal != null && context.Ticket.Principal.Identity.IsAuthenticated)
|
|
||||||
{
|
|
||||||
context.Validated();
|
|
||||||
}
|
|
||||||
return Task.FromResult<object>(null);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
public interface IAuthenticationTokenProvider
|
|
||||||
{
|
|
||||||
void Create(AuthenticationTokenCreateContext context);
|
|
||||||
Task CreateAsync(AuthenticationTokenCreateContext context);
|
|
||||||
void Receive(AuthenticationTokenReceiveContext context);
|
|
||||||
Task ReceiveAsync(AuthenticationTokenReceiveContext context);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,172 +0,0 @@
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Interface for OAuthAuthorizationServerOptions.Provider property used by Authorization
|
|
||||||
/// Server to communicate with the web application while processing requests.
|
|
||||||
/// </summary>
|
|
||||||
public interface IOAuthAuthorizationServerProvider
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Called to determine if an incoming request is treated as an Authorize or Token
|
|
||||||
/// endpoint. If Options.AuthorizeEndpointPath or Options.TokenEndpointPath
|
|
||||||
/// are assigned values, then handling this event is optional and context.IsAuthorizeEndpoint and context.IsTokenEndpoint
|
|
||||||
/// will already be true if the request path matches.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task MatchEndpoint(OAuthMatchContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to validate that the context.ClientId is a registered "client_id", and that the context.RedirectUri a "redirect_uri"
|
|
||||||
/// registered for that client. This only occurs when processing the Authorize endpoint. The application MUST implement this
|
|
||||||
/// call, and it MUST validate both of those factors before calling context.Validated. If the context.Validated method is called
|
|
||||||
/// with a given redirectUri parameter, then IsValidated will only become true if the incoming redirect URI matches the given redirect URI.
|
|
||||||
/// If context.Validated is not called the request will not proceed further.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to validate that the origin of the request is a registered "client_id", and that the correct credentials for that client are
|
|
||||||
/// present on the request. If the web application accepts Basic authentication credentials,
|
|
||||||
/// context.TryGetBasicCredentials(out clientId, out clientSecret) may be called to acquire those values if present in the request header. If the web
|
|
||||||
/// application accepts "client_id" and "client_secret" as form encoded POST parameters,
|
|
||||||
/// context.TryGetFormCredentials(out clientId, out clientSecret) may be called to acquire those values if present in the request body.
|
|
||||||
/// If context.Validated is not called the request will not proceed further.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called for each request to the Authorize endpoint to determine if the request is valid and should continue.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to assume well-formed requests, with
|
|
||||||
/// validated client redirect URI, should continue processing. An application may add any additional constraints.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task ValidateAuthorizeRequest(OAuthValidateAuthorizeRequestContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called for each request to the Token endpoint to determine if the request is valid and should continue.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to assume well-formed requests, with
|
|
||||||
/// validated client credentials, should continue processing. An application may add any additional constraints.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task ValidateTokenRequest(OAuthValidateTokenRequestContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "authorization_code". This occurs after the Authorize
|
|
||||||
/// endpoint as redirected the user-agent back to the client with a "code" parameter, and the client is exchanging that for an "access_token".
|
|
||||||
/// The claims and properties
|
|
||||||
/// associated with the authorization code are present in the context.Ticket. The application must call context.Validated to instruct the Authorization
|
|
||||||
/// Server middleware to issue an access token based on those claims and properties. The call to context.Validated may be given a different
|
|
||||||
/// AuthenticationTicket or ClaimsIdentity in order to control which information flows from authorization code to access token.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to flow information from the authorization code to
|
|
||||||
/// the access token unmodified.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.1.3
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task GrantAuthorizationCode(OAuthGrantAuthorizationCodeContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "refresh_token". This occurs if your application has issued a "refresh_token"
|
|
||||||
/// along with the "access_token", and the client is attempting to use the "refresh_token" to acquire a new "access_token", and possibly a new "refresh_token".
|
|
||||||
/// To issue a refresh token the an Options.RefreshTokenProvider must be assigned to create the value which is returned. The claims and properties
|
|
||||||
/// associated with the refresh token are present in the context.Ticket. The application must call context.Validated to instruct the
|
|
||||||
/// Authorization Server middleware to issue an access token based on those claims and properties. The call to context.Validated may
|
|
||||||
/// be given a different AuthenticationTicket or ClaimsIdentity in order to control which information flows from the refresh token to
|
|
||||||
/// the access token. The default behavior when using the OAuthAuthorizationServerProvider is to flow information from the refresh token to
|
|
||||||
/// the access token unmodified.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-6
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task GrantRefreshToken(OAuthGrantRefreshTokenContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "password". This occurs when the user has provided name and password
|
|
||||||
/// credentials directly into the client application's user interface, and the client application is using those to acquire an "access_token" and
|
|
||||||
/// optional "refresh_token". If the web application supports the
|
|
||||||
/// resource owner credentials grant type it must validate the context.Username and context.Password as appropriate. To issue an
|
|
||||||
/// access token the context.Validated must be called with a new ticket containing the claims about the resource owner which should be associated
|
|
||||||
/// with the access token. The application should take appropriate measures to ensure that the endpoint isn’t abused by malicious callers. .
|
|
||||||
/// The default behavior is to reject this grant type.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.3.2
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "client_credentials". This occurs when a registered client
|
|
||||||
/// application wishes to acquire an "access_token" to interact with protected resources on it's own behalf, rather than on behalf of an authenticated user.
|
|
||||||
/// If the web application supports the client credentials it may assume the context.ClientId has been validated by the ValidateClientAuthentication call.
|
|
||||||
/// To issue an access token the context.Validated must be called with a new ticket containing the claims about the client application which should be associated
|
|
||||||
/// with the access token. The application should take appropriate measures to ensure that the endpoint isn’t abused by malicious callers.
|
|
||||||
/// The default behavior is to reject this grant type.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.4.2
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task GrantClientCredentials(OAuthGrantClientCredentialsContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token andpoint arrives with a "grant_type" of any other value. If the application supports custom grant types
|
|
||||||
/// it is entirely responsible for determining if the request should result in an access_token. If context.Validated is called with ticket
|
|
||||||
/// information the response body is produced in the same way as the other standard grant types. If additional response parameters must be
|
|
||||||
/// included they may be added in the final TokenEndpoint call.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.5
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task GrantCustomExtension(OAuthGrantCustomExtensionContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called at the final stage of an incoming Authorize endpoint request before the execution continues on to the web application component
|
|
||||||
/// responsible for producing the html response. Anything present in the OWIN pipeline following the Authorization Server may produce the
|
|
||||||
/// response for the Authorize page. If running on IIS any ASP.NET technology running on the server may produce the response for the
|
|
||||||
/// Authorize page. If the web application wishes to produce the response directly in the AuthorizeEndpoint call it may write to the
|
|
||||||
/// context.Response directly and should call context.RequestCompleted to stop other handlers from executing. If the web application wishes
|
|
||||||
/// to grant the authorization directly in the AuthorizeEndpoint call it cay call context.OwinContext.Authentication.SignIn with the
|
|
||||||
/// appropriate ClaimsIdentity and should call context.RequestCompleted to stop other handlers from executing.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called at the final stage of a successful Token endpoint request. An application may implement this call in order to do any final
|
|
||||||
/// modification of the claims being used to issue access or refresh tokens. This call may also be used in order to add additional
|
|
||||||
/// response parameters to the Token endpoint's json response body.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task TokenEndpoint(OAuthTokenEndpointContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called before the AuthorizationEndpoint redirects its response to the caller. The response could be the
|
|
||||||
/// token, when using implicit flow or the AuthorizationEndpoint when using authorization code flow.
|
|
||||||
/// An application may implement this call in order to do any final modification of the claims being used
|
|
||||||
/// to issue access or refresh tokens. This call may also be used in order to add additional
|
|
||||||
/// response parameters to the authorization endpoint's response.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
Task AuthorizationEndpointResponse(OAuthAuthorizationEndpointResponseContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called before the TokenEndpoint redirects its response to the caller.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
SOURCE_DIR=../..
|
|
||||||
MAKEFILE_DIR=$(SOURCE_DIR)/scripts/make
|
|
||||||
include $(MAKEFILE_DIR)/dnx.mk
|
|
||||||
include $(MAKEFILE_DIR)/versioning.mk
|
|
||||||
|
|
||||||
all: $(BINTARGETPATH)
|
|
||||||
|
|
||||||
|
|
@ -1,808 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Microsoft.AspNet.Http.Authentication;
|
|
||||||
using Microsoft.AspNet.Http.Features.Authentication;
|
|
||||||
using Microsoft.AspNet.WebUtilities;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
public class OAuthAuthorizationServerHandler : AuthenticationHandler<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
#region non-Public Members
|
|
||||||
|
|
||||||
private AuthorizeEndpointRequest _authorizeEndpointRequest;
|
|
||||||
|
|
||||||
private OAuthValidateClientRedirectUriContext _clientContext;
|
|
||||||
|
|
||||||
private Task SendErrorAsJsonAsync(BaseValidatingContext<OAuthAuthorizationServerOptions> validatingContext)
|
|
||||||
{
|
|
||||||
string error = validatingContext.HasError ? validatingContext.Error : Constants.Errors.InvalidRequest;
|
|
||||||
string errorDescription = validatingContext.HasError ? validatingContext.ErrorDescription : null;
|
|
||||||
string errorUri = validatingContext.HasError ? validatingContext.ErrorUri : null;
|
|
||||||
|
|
||||||
string body;
|
|
||||||
|
|
||||||
MemoryStream stream, memoryStream = null;
|
|
||||||
|
|
||||||
StreamWriter streamWriter;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
stream = memoryStream = new MemoryStream();
|
|
||||||
|
|
||||||
streamWriter = new StreamWriter(memoryStream);
|
|
||||||
|
|
||||||
using (var writer = new JsonTextWriter(streamWriter))
|
|
||||||
{
|
|
||||||
memoryStream = null;
|
|
||||||
|
|
||||||
streamWriter = null;
|
|
||||||
|
|
||||||
writer.WriteStartObject();
|
|
||||||
writer.WritePropertyName(Constants.Parameters.Error);
|
|
||||||
writer.WriteValue(error);
|
|
||||||
if (!string.IsNullOrEmpty(errorDescription))
|
|
||||||
{
|
|
||||||
writer.WritePropertyName(Constants.Parameters.ErrorDescription);
|
|
||||||
writer.WriteValue(errorDescription);
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(errorUri))
|
|
||||||
{
|
|
||||||
writer.WritePropertyName(Constants.Parameters.ErrorUri);
|
|
||||||
writer.WriteValue(errorUri);
|
|
||||||
}
|
|
||||||
writer.WriteEndObject();
|
|
||||||
writer.Flush();
|
|
||||||
body = Encoding.UTF8.GetString(stream.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (memoryStream != null)
|
|
||||||
memoryStream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Response.StatusCode = 400;
|
|
||||||
Response.ContentType = "application/json;charset=UTF-8";
|
|
||||||
Response.Headers["Cache-Control"] = "no-cache";
|
|
||||||
Response.Headers["Pragma"] = "no-cache";
|
|
||||||
Response.Headers["Expires"] = "-1";
|
|
||||||
Response.Headers["Content-Length"] = body.Length.ToString(CultureInfo.InvariantCulture);
|
|
||||||
return Response.WriteAsync(body, Context.RequestAborted);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> SendErrorPageAsync(string error, string errorDescription, string errorUri)
|
|
||||||
{
|
|
||||||
Response.StatusCode = 400;
|
|
||||||
Response.Headers["Cache-Control"] = "no-cache";
|
|
||||||
Response.Headers["Pragma"] = "no-cache";
|
|
||||||
Response.Headers["Expires"] = "-1";
|
|
||||||
|
|
||||||
if (Options.ApplicationCanDisplayErrors)
|
|
||||||
{
|
|
||||||
Context.Items["oauth.Error"] = error;
|
|
||||||
Context.Items["oauth.ErrorDescription"] = errorDescription;
|
|
||||||
Context.Items["oauth.ErrorUri"] = errorUri;
|
|
||||||
|
|
||||||
// request is not handled - pass through to application for rendering
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var memory = new MemoryStream();
|
|
||||||
string body;
|
|
||||||
using (var writer = new StreamWriter(memory))
|
|
||||||
{
|
|
||||||
writer.WriteLine("error: {0}", error);
|
|
||||||
if (!string.IsNullOrEmpty(errorDescription))
|
|
||||||
{
|
|
||||||
writer.WriteLine("error_description: {0}", errorDescription);
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(errorUri))
|
|
||||||
{
|
|
||||||
writer.WriteLine("error_uri: {0}", errorUri);
|
|
||||||
}
|
|
||||||
writer.Flush();
|
|
||||||
body = Encoding.UTF8.GetString(memory.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
Response.ContentType = "text/plain;charset=UTF-8";
|
|
||||||
Response.Headers["Content-Length"] = body.Length.ToString(CultureInfo.InvariantCulture);
|
|
||||||
await Response.WriteAsync(body, Context.RequestAborted);
|
|
||||||
// request is handled, does not pass on to application
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<bool> SendErrorRedirectAsync(OAuthValidateClientRedirectUriContext clientContext, BaseValidatingContext<OAuthAuthorizationServerOptions> validatingContext)
|
|
||||||
{
|
|
||||||
if (clientContext == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("clientContext");
|
|
||||||
}
|
|
||||||
|
|
||||||
string error = validatingContext.HasError ? validatingContext.Error : Constants.Errors.InvalidRequest;
|
|
||||||
string errorDescription = validatingContext.HasError ? validatingContext.ErrorDescription : null;
|
|
||||||
string errorUri = validatingContext.HasError ? validatingContext.ErrorUri : null;
|
|
||||||
|
|
||||||
if (!clientContext.IsValidated)
|
|
||||||
{
|
|
||||||
// write error in response body if client_id or redirect_uri have not been validated
|
|
||||||
return SendErrorPageAsync(error, errorDescription, errorUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
// redirect with error if client_id and redirect_uri have been validated
|
|
||||||
string location = QueryHelpers.AddQueryString(clientContext.RedirectUri, Constants.Parameters.Error, error);
|
|
||||||
if (!string.IsNullOrEmpty(errorDescription))
|
|
||||||
{
|
|
||||||
location = QueryHelpers.AddQueryString(location, Constants.Parameters.ErrorDescription, errorDescription);
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(errorUri))
|
|
||||||
{
|
|
||||||
location = QueryHelpers.AddQueryString(location, Constants.Parameters.ErrorUri, errorUri);
|
|
||||||
}
|
|
||||||
Response.Redirect(location);
|
|
||||||
// request is handled, does not pass on to application
|
|
||||||
return Task.FromResult(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AuthenticationTicket ReturnOutcome(OAuthValidateTokenRequestContext validatingContext, BaseValidatingContext<OAuthAuthorizationServerOptions> grantContext, AuthenticationTicket ticket, string defaultError)
|
|
||||||
{
|
|
||||||
if (!validatingContext.IsValidated)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
if (!grantContext.IsValidated)
|
|
||||||
{
|
|
||||||
if (grantContext.HasError)
|
|
||||||
{
|
|
||||||
validatingContext.SetError(grantContext.Error, grantContext.ErrorDescription, grantContext.ErrorUri);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
validatingContext.SetError(defaultError);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ticket == null)
|
|
||||||
{
|
|
||||||
validatingContext.SetError(defaultError);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ticket;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<AuthenticationTicket> InvokeTokenEndpointAuthorizationCodeGrantAsync(OAuthValidateTokenRequestContext validatingContext, DateTimeOffset currentUtc)
|
|
||||||
{
|
|
||||||
TokenEndpointRequest tokenEndpointRequest = validatingContext.TokenRequest;
|
|
||||||
|
|
||||||
var authorizationCodeContext = new AuthenticationTokenReceiveContext(Context, Options.AuthorizationCodeFormat, tokenEndpointRequest.AuthorizationCodeGrant.Code);
|
|
||||||
|
|
||||||
await Options.AuthorizationCodeProvider.ReceiveAsync(authorizationCodeContext);
|
|
||||||
|
|
||||||
AuthenticationTicket ticket = authorizationCodeContext.Ticket;
|
|
||||||
|
|
||||||
if (ticket == null)
|
|
||||||
{
|
|
||||||
Logger.LogError("invalid authorization code");
|
|
||||||
validatingContext.SetError(Constants.Errors.InvalidGrant);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ticket.Properties.ExpiresUtc.HasValue ||
|
|
||||||
ticket.Properties.ExpiresUtc < currentUtc)
|
|
||||||
{
|
|
||||||
Logger.LogError("expired authorization code");
|
|
||||||
validatingContext.SetError(Constants.Errors.InvalidGrant);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string clientId;
|
|
||||||
if (!ticket.Properties.Items.TryGetValue(Constants.Extra.ClientId, out clientId) ||
|
|
||||||
!string.Equals(clientId, validatingContext.ClientContext.ClientId, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
Logger.LogError("authorization code does not contain matching client_id");
|
|
||||||
validatingContext.SetError(Constants.Errors.InvalidGrant);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
string redirectUri;
|
|
||||||
if (ticket.Properties.Items.TryGetValue(Constants.Extra.RedirectUri, out redirectUri))
|
|
||||||
{
|
|
||||||
ticket.Properties.Items.Remove(Constants.Extra.RedirectUri);
|
|
||||||
if (!string.Equals(redirectUri, tokenEndpointRequest.AuthorizationCodeGrant.RedirectUri, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
Logger.LogError("authorization code does not contain matching redirect_uri");
|
|
||||||
validatingContext.SetError(Constants.Errors.InvalidGrant);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Options.Provider.ValidateTokenRequest(validatingContext);
|
|
||||||
|
|
||||||
var grantContext = new OAuthGrantAuthorizationCodeContext(
|
|
||||||
Context, Options, ticket);
|
|
||||||
|
|
||||||
if (validatingContext.IsValidated)
|
|
||||||
{
|
|
||||||
await Options.Provider.GrantAuthorizationCode(grantContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ReturnOutcome(validatingContext, grantContext, grantContext.Ticket, Constants.Errors.InvalidGrant);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<AuthenticationTicket> InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync(OAuthValidateTokenRequestContext validatingContext, DateTimeOffset currentUtc)
|
|
||||||
{
|
|
||||||
TokenEndpointRequest tokenEndpointRequest = validatingContext.TokenRequest;
|
|
||||||
|
|
||||||
await Options.Provider.ValidateTokenRequest(validatingContext);
|
|
||||||
|
|
||||||
var grantContext = new OAuthGrantResourceOwnerCredentialsContext(
|
|
||||||
Context,
|
|
||||||
Options,
|
|
||||||
validatingContext.ClientContext.ClientId,
|
|
||||||
tokenEndpointRequest.ResourceOwnerPasswordCredentialsGrant.UserName,
|
|
||||||
tokenEndpointRequest.ResourceOwnerPasswordCredentialsGrant.Password,
|
|
||||||
tokenEndpointRequest.ResourceOwnerPasswordCredentialsGrant.Scope
|
|
||||||
);
|
|
||||||
|
|
||||||
if (validatingContext.IsValidated)
|
|
||||||
await Options.Provider.GrantResourceOwnerCredentials(grantContext);
|
|
||||||
|
|
||||||
return ReturnOutcome(validatingContext, grantContext, grantContext.Ticket, Constants.Errors.InvalidGrant);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<AuthenticationTicket> InvokeTokenEndpointClientCredentialsGrantAsync(OAuthValidateTokenRequestContext validatingContext, DateTimeOffset currentUtc)
|
|
||||||
{
|
|
||||||
TokenEndpointRequest tokenEndpointRequest = validatingContext.TokenRequest;
|
|
||||||
|
|
||||||
await Options.Provider.ValidateTokenRequest(validatingContext);
|
|
||||||
|
|
||||||
if (!validatingContext.IsValidated)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var grantContext = new OAuthGrantClientCredentialsContext(Context, Options, validatingContext.ClientContext.ClientId, tokenEndpointRequest.ClientCredentialsGrant.Scope);
|
|
||||||
|
|
||||||
await Options.Provider.GrantClientCredentials(grantContext);
|
|
||||||
|
|
||||||
return ReturnOutcome(validatingContext, grantContext, grantContext.Ticket, Constants.Errors.UnauthorizedClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<AuthenticationTicket> InvokeTokenEndpointRefreshTokenGrantAsync(OAuthValidateTokenRequestContext validatingContext, DateTimeOffset currentUtc)
|
|
||||||
{
|
|
||||||
TokenEndpointRequest tokenEndpointRequest = validatingContext.TokenRequest;
|
|
||||||
|
|
||||||
var refreshTokenContext = new AuthenticationTokenReceiveContext(Context, Options.RefreshTokenFormat, tokenEndpointRequest.RefreshTokenGrant.RefreshToken);
|
|
||||||
|
|
||||||
await Options.RefreshTokenProvider.ReceiveAsync(refreshTokenContext);
|
|
||||||
|
|
||||||
AuthenticationTicket ticket = refreshTokenContext.Ticket;
|
|
||||||
|
|
||||||
if (ticket == null)
|
|
||||||
{
|
|
||||||
Logger.LogError("invalid refresh token");
|
|
||||||
validatingContext.SetError(Constants.Errors.InvalidGrant);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ticket.Properties.ExpiresUtc.HasValue || ticket.Properties.ExpiresUtc < currentUtc)
|
|
||||||
{
|
|
||||||
Logger.LogError("expired refresh token");
|
|
||||||
validatingContext.SetError(Constants.Errors.InvalidGrant);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Options.Provider.ValidateTokenRequest(validatingContext);
|
|
||||||
|
|
||||||
var grantContext = new OAuthGrantRefreshTokenContext(Context, Options, ticket, validatingContext.ClientContext.ClientId);
|
|
||||||
|
|
||||||
if (validatingContext.IsValidated)
|
|
||||||
await Options.Provider.GrantRefreshToken(grantContext);
|
|
||||||
|
|
||||||
return ReturnOutcome(validatingContext, grantContext, grantContext.Ticket, Constants.Errors.InvalidGrant);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<AuthenticationTicket> InvokeTokenEndpointCustomGrantAsync(OAuthValidateTokenRequestContext validatingContext, DateTimeOffset currentUtc)
|
|
||||||
{
|
|
||||||
TokenEndpointRequest tokenEndpointRequest = validatingContext.TokenRequest;
|
|
||||||
|
|
||||||
await Options.Provider.ValidateTokenRequest(validatingContext);
|
|
||||||
|
|
||||||
var grantContext = new OAuthGrantCustomExtensionContext(Context, Options, validatingContext.ClientContext.ClientId, tokenEndpointRequest.GrantType, tokenEndpointRequest.CustomExtensionGrant.Parameters);
|
|
||||||
|
|
||||||
if (validatingContext.IsValidated)
|
|
||||||
await Options.Provider.GrantCustomExtension(grantContext);
|
|
||||||
|
|
||||||
return ReturnOutcome(validatingContext, grantContext, grantContext.Ticket, Constants.Errors.UnsupportedGrantType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<bool> InvokeAuthorizeEndpointAsync()
|
|
||||||
{
|
|
||||||
var authorizeRequest = new AuthorizeEndpointRequest(Request.Query);
|
|
||||||
|
|
||||||
var clientContext = new OAuthValidateClientRedirectUriContext(Context, Options, authorizeRequest.ClientId, authorizeRequest.RedirectUri);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(authorizeRequest.RedirectUri))
|
|
||||||
{
|
|
||||||
bool acceptableUri = true;
|
|
||||||
|
|
||||||
Uri validatingUri;
|
|
||||||
|
|
||||||
if (!Uri.TryCreate(authorizeRequest.RedirectUri, UriKind.Absolute, out validatingUri))
|
|
||||||
{
|
|
||||||
// The redirection endpoint URI MUST be an absolute URI
|
|
||||||
// http://tools.ietf.org/html/rfc6749#section-3.1.2
|
|
||||||
acceptableUri = false;
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrEmpty(validatingUri.Fragment))
|
|
||||||
{
|
|
||||||
// The endpoint URI MUST NOT include a fragment component.
|
|
||||||
// http://tools.ietf.org/html/rfc6749#section-3.1.2
|
|
||||||
acceptableUri = false;
|
|
||||||
}
|
|
||||||
else if (!Options.AllowInsecureHttp && string.Equals(validatingUri.Scheme, "http", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
// The redirection endpoint SHOULD require the use of TLS
|
|
||||||
// http://tools.ietf.org/html/rfc6749#section-3.1.2.1
|
|
||||||
acceptableUri = false;
|
|
||||||
}
|
|
||||||
if (!acceptableUri)
|
|
||||||
{
|
|
||||||
clientContext.SetError(Constants.Errors.InvalidRequest);
|
|
||||||
|
|
||||||
return await SendErrorRedirectAsync(clientContext, clientContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Options.Provider.ValidateClientRedirectUri(clientContext);
|
|
||||||
|
|
||||||
if (!clientContext.IsValidated)
|
|
||||||
{
|
|
||||||
Logger.LogVerbose("Unable to validate client information (redirect_uri)");
|
|
||||||
|
|
||||||
return await SendErrorRedirectAsync(clientContext, clientContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
var validatingContext = new OAuthValidateAuthorizeRequestContext(Context, Options, authorizeRequest, clientContext);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(authorizeRequest.ResponseType))
|
|
||||||
{
|
|
||||||
Logger.LogVerbose("Authorize endpoint request missing required response_type parameter");
|
|
||||||
|
|
||||||
validatingContext.SetError(Constants.Errors.InvalidRequest);
|
|
||||||
}
|
|
||||||
else if (!authorizeRequest.IsAuthorizationCodeGrantType && !authorizeRequest.IsImplicitGrantType)
|
|
||||||
{
|
|
||||||
Logger.LogVerbose("Authorize endpoint request contains unsupported response_type parameter");
|
|
||||||
|
|
||||||
validatingContext.SetError(Constants.Errors.UnsupportedResponseType);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Options.Provider.ValidateAuthorizeRequest(validatingContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validatingContext.IsValidated)
|
|
||||||
{
|
|
||||||
// an invalid request is not processed further
|
|
||||||
return await SendErrorRedirectAsync(clientContext, validatingContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
_clientContext = clientContext;
|
|
||||||
|
|
||||||
_authorizeEndpointRequest = authorizeRequest;
|
|
||||||
|
|
||||||
var authorizeEndpointContext = new OAuthAuthorizeEndpointContext(Context, Options, authorizeRequest);
|
|
||||||
|
|
||||||
await Options.Provider.AuthorizeEndpoint(authorizeEndpointContext);
|
|
||||||
|
|
||||||
return authorizeEndpointContext.IsRequestCompleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task InvokeTokenEndpointAsync()
|
|
||||||
{
|
|
||||||
DateTimeOffset currentUtc = Options.SystemClock.UtcNow;
|
|
||||||
|
|
||||||
// remove milliseconds in case they don't round-trip
|
|
||||||
currentUtc = currentUtc.Subtract(TimeSpan.FromMilliseconds(currentUtc.Millisecond));
|
|
||||||
|
|
||||||
IFormCollection form = await Request.ReadFormAsync();
|
|
||||||
|
|
||||||
var clientContext = new OAuthValidateClientAuthenticationContext(Context, Options, form);
|
|
||||||
|
|
||||||
await Options.Provider.ValidateClientAuthentication(clientContext);
|
|
||||||
|
|
||||||
if (!clientContext.IsValidated)
|
|
||||||
{
|
|
||||||
Logger.LogError("clientID is not valid.");
|
|
||||||
|
|
||||||
if (!clientContext.HasError)
|
|
||||||
clientContext.SetError(Constants.Errors.InvalidClient);
|
|
||||||
|
|
||||||
await SendErrorAsJsonAsync(clientContext);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenEndpointRequest = new TokenEndpointRequest(form);
|
|
||||||
|
|
||||||
var validatingContext = new OAuthValidateTokenRequestContext(Context, Options, tokenEndpointRequest, clientContext);
|
|
||||||
|
|
||||||
AuthenticationTicket ticket = null;
|
|
||||||
if (tokenEndpointRequest.IsAuthorizationCodeGrantType)
|
|
||||||
{
|
|
||||||
// Authorization Code Grant http://tools.ietf.org/html/rfc6749#section-4.1
|
|
||||||
// Access Token Request http://tools.ietf.org/html/rfc6749#section-4.1.3
|
|
||||||
ticket = await InvokeTokenEndpointAuthorizationCodeGrantAsync(validatingContext, currentUtc);
|
|
||||||
}
|
|
||||||
else if (tokenEndpointRequest.IsResourceOwnerPasswordCredentialsGrantType)
|
|
||||||
{
|
|
||||||
// Resource Owner Password Credentials Grant http://tools.ietf.org/html/rfc6749#section-4.3
|
|
||||||
// Access Token Request http://tools.ietf.org/html/rfc6749#section-4.3.2
|
|
||||||
ticket = await InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync(validatingContext, currentUtc);
|
|
||||||
}
|
|
||||||
else if (tokenEndpointRequest.IsClientCredentialsGrantType)
|
|
||||||
{
|
|
||||||
// Client Credentials Grant http://tools.ietf.org/html/rfc6749#section-4.4
|
|
||||||
// Access Token Request http://tools.ietf.org/html/rfc6749#section-4.4.2
|
|
||||||
ticket = await InvokeTokenEndpointClientCredentialsGrantAsync(validatingContext, currentUtc);
|
|
||||||
}
|
|
||||||
else if (tokenEndpointRequest.IsRefreshTokenGrantType)
|
|
||||||
{
|
|
||||||
// Refreshing an Access Token
|
|
||||||
// http://tools.ietf.org/html/rfc6749#section-6
|
|
||||||
ticket = await InvokeTokenEndpointRefreshTokenGrantAsync(validatingContext, currentUtc);
|
|
||||||
}
|
|
||||||
else if (tokenEndpointRequest.IsCustomExtensionGrantType)
|
|
||||||
{
|
|
||||||
// Defining New Authorization Grant Types
|
|
||||||
// http://tools.ietf.org/html/rfc6749#section-8.3
|
|
||||||
ticket = await InvokeTokenEndpointCustomGrantAsync(validatingContext, currentUtc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Error Response http://tools.ietf.org/html/rfc6749#section-5.2
|
|
||||||
// The authorization grant type is not supported by the
|
|
||||||
// authorization server.
|
|
||||||
Logger.LogError("grant type is not recognized");
|
|
||||||
|
|
||||||
validatingContext.SetError(Constants.Errors.UnsupportedGrantType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ticket == null)
|
|
||||||
{
|
|
||||||
await SendErrorAsJsonAsync(validatingContext);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ticket.Properties.IssuedUtc = currentUtc;
|
|
||||||
ticket.Properties.ExpiresUtc = currentUtc.Add(Options.AccessTokenExpireTimeSpan);
|
|
||||||
|
|
||||||
var tokenEndpointContext = new OAuthTokenEndpointContext(Context, Options, ticket, tokenEndpointRequest);
|
|
||||||
|
|
||||||
await Options.Provider.TokenEndpoint(tokenEndpointContext);
|
|
||||||
|
|
||||||
if (tokenEndpointContext.TokenIssued)
|
|
||||||
{
|
|
||||||
ticket = new AuthenticationTicket(tokenEndpointContext.Principal, tokenEndpointContext.Properties, tokenEndpointContext.Options.AuthenticationScheme);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.LogError("Token was not issued to tokenEndpointContext");
|
|
||||||
validatingContext.SetError(Constants.Errors.InvalidGrant);
|
|
||||||
await SendErrorAsJsonAsync(validatingContext);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var accessTokenContext = new AuthenticationTokenCreateContext(
|
|
||||||
Context,
|
|
||||||
Options.AccessTokenFormat,
|
|
||||||
ticket);
|
|
||||||
|
|
||||||
await Options.AccessTokenProvider.CreateAsync(accessTokenContext);
|
|
||||||
|
|
||||||
string accessToken = accessTokenContext.Token;
|
|
||||||
if (string.IsNullOrEmpty(accessToken))
|
|
||||||
{
|
|
||||||
accessToken = accessTokenContext.SerializeTicket();
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTimeOffset? accessTokenExpiresUtc = ticket.Properties.ExpiresUtc;
|
|
||||||
|
|
||||||
var refreshTokenCreateContext = new AuthenticationTokenCreateContext(Context, Options.RefreshTokenFormat, accessTokenContext.Ticket);
|
|
||||||
|
|
||||||
await Options.RefreshTokenProvider.CreateAsync(refreshTokenCreateContext);
|
|
||||||
|
|
||||||
string refreshToken = refreshTokenCreateContext.Token;
|
|
||||||
|
|
||||||
var tokenEndpointResponseContext = new OAuthTokenEndpointResponseContext(Context, Options, ticket, tokenEndpointRequest, accessToken, tokenEndpointContext.AdditionalResponseParameters);
|
|
||||||
|
|
||||||
await Options.Provider.TokenEndpointResponse(tokenEndpointResponseContext);
|
|
||||||
|
|
||||||
MemoryStream stream, memoryStream = null;
|
|
||||||
|
|
||||||
string body;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
stream = memoryStream = new MemoryStream();
|
|
||||||
|
|
||||||
using (var writer = new JsonTextWriter(new StreamWriter(memoryStream)))
|
|
||||||
{
|
|
||||||
memoryStream = null;
|
|
||||||
|
|
||||||
writer.WriteStartObject();
|
|
||||||
writer.WritePropertyName(Constants.Parameters.AccessToken);
|
|
||||||
writer.WriteValue(accessToken);
|
|
||||||
writer.WritePropertyName(Constants.Parameters.TokenType);
|
|
||||||
writer.WriteValue(Constants.TokenTypes.Bearer);
|
|
||||||
|
|
||||||
if (accessTokenExpiresUtc.HasValue)
|
|
||||||
{
|
|
||||||
TimeSpan? expiresTimeSpan = accessTokenExpiresUtc - currentUtc;
|
|
||||||
var expiresIn = (long)expiresTimeSpan.Value.TotalSeconds;
|
|
||||||
if (expiresIn > 0)
|
|
||||||
{
|
|
||||||
writer.WritePropertyName(Constants.Parameters.ExpiresIn);
|
|
||||||
writer.WriteValue(expiresIn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(refreshToken))
|
|
||||||
{
|
|
||||||
writer.WritePropertyName(Constants.Parameters.RefreshToken);
|
|
||||||
writer.WriteValue(refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var additionalResponseParameter in tokenEndpointResponseContext.AdditionalResponseParameters)
|
|
||||||
{
|
|
||||||
writer.WritePropertyName(additionalResponseParameter.Key);
|
|
||||||
writer.WriteValue(additionalResponseParameter.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.WriteEndObject();
|
|
||||||
writer.Flush();
|
|
||||||
body = Encoding.UTF8.GetString(stream.ToArray());
|
|
||||||
|
|
||||||
Response.ContentType = "application/json;charset=UTF-8";
|
|
||||||
Response.Headers["Cache-Control"] = "no-cache";
|
|
||||||
Response.Headers["Pragma"] = "no-cache";
|
|
||||||
Response.Headers["Expires"] = "-1";
|
|
||||||
Response.ContentLength = Encoding.UTF8.GetByteCount(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (memoryStream != null)
|
|
||||||
memoryStream.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
await Response.WriteAsync(body, Encoding.UTF8, Context.RequestAborted);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Appender
|
|
||||||
{
|
|
||||||
private readonly char _delimiter;
|
|
||||||
private readonly StringBuilder _sb;
|
|
||||||
private bool _hasDelimiter;
|
|
||||||
|
|
||||||
public Appender(string value, char delimiter)
|
|
||||||
{
|
|
||||||
_sb = new StringBuilder(value);
|
|
||||||
_delimiter = delimiter;
|
|
||||||
_hasDelimiter = value.IndexOf(delimiter) != -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Appender Append(string name, string value)
|
|
||||||
{
|
|
||||||
_sb.Append(_hasDelimiter ? '&' : _delimiter)
|
|
||||||
.Append(Uri.EscapeDataString(name))
|
|
||||||
.Append('=')
|
|
||||||
.Append(Uri.EscapeDataString(value));
|
|
||||||
|
|
||||||
_hasDelimiter = true;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return _sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
|
||||||
{
|
|
||||||
return Task.FromResult<AuthenticateResult>(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Members
|
|
||||||
|
|
||||||
public override async Task<bool> HandleRequestAsync()
|
|
||||||
{
|
|
||||||
var matchRequestContext = new OAuthMatchContext(Context, Options);
|
|
||||||
|
|
||||||
if (Options.AuthorizeEndpointPath.HasValue && Options.AuthorizeEndpointPath == Request.Path)
|
|
||||||
{
|
|
||||||
matchRequestContext.MatchesAuthorizeEndpoint();
|
|
||||||
}
|
|
||||||
else if (Options.TokenEndpointPath.HasValue && Options.TokenEndpointPath == Request.Path)
|
|
||||||
{
|
|
||||||
matchRequestContext.MatchesTokenEndpoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
await Options.Provider.MatchEndpoint(matchRequestContext);
|
|
||||||
|
|
||||||
if (matchRequestContext.HandledResponse)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (matchRequestContext.Skipped)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (matchRequestContext.IsAuthorizeEndpoint || matchRequestContext.IsTokenEndpoint)
|
|
||||||
{
|
|
||||||
if (!Options.AllowInsecureHttp && !Context.Request.IsHttps)
|
|
||||||
{
|
|
||||||
Logger.LogWarning("Authorization server ignoring http request because AllowInsecureHttp is false.");
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchRequestContext.IsAuthorizeEndpoint)
|
|
||||||
return await InvokeAuthorizeEndpointAsync();
|
|
||||||
|
|
||||||
if (matchRequestContext.IsTokenEndpoint)
|
|
||||||
{
|
|
||||||
await InvokeTokenEndpointAsync();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task HandleSignInAsync(SignInContext context)
|
|
||||||
{
|
|
||||||
// only successful results of an authorize request are altered
|
|
||||||
if (_clientContext == null || _authorizeEndpointRequest == null || Response.StatusCode != 200)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (context?.Principal == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
AuthenticationResponseGrant signin = new AuthenticationResponseGrant(context.Principal, new AuthenticationProperties(context.Properties));
|
|
||||||
|
|
||||||
var returnParameter = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
if (_authorizeEndpointRequest.IsAuthorizationCodeGrantType)
|
|
||||||
{
|
|
||||||
DateTimeOffset currentUtc = Options.SystemClock.UtcNow;
|
|
||||||
signin.Properties.IssuedUtc = currentUtc;
|
|
||||||
signin.Properties.ExpiresUtc = currentUtc.Add(Options.AuthorizationCodeExpireTimeSpan);
|
|
||||||
|
|
||||||
// associate client_id with all subsequent tickets
|
|
||||||
signin.Properties.Items[Constants.Extra.ClientId] = _authorizeEndpointRequest.ClientId;
|
|
||||||
if (!string.IsNullOrEmpty(_authorizeEndpointRequest.RedirectUri))
|
|
||||||
{
|
|
||||||
// keep original request parameter for later comparison
|
|
||||||
signin.Properties.Items[Constants.Extra.RedirectUri] = _authorizeEndpointRequest.RedirectUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenCreationContext = new AuthenticationTokenCreateContext(Context, Options.AuthorizationCodeFormat, new AuthenticationTicket(signin.Principal, signin.Properties, signin.Identity.AuthenticationType));
|
|
||||||
|
|
||||||
await Options.AuthorizationCodeProvider.CreateAsync(tokenCreationContext);
|
|
||||||
|
|
||||||
string code = tokenCreationContext.Token;
|
|
||||||
if (string.IsNullOrEmpty(code))
|
|
||||||
{
|
|
||||||
Logger.LogError("response_type code requires an Options.AuthorizationCodeProvider implementing a single-use token.");
|
|
||||||
var errorContext = new OAuthValidateAuthorizeRequestContext(Context, Options, _authorizeEndpointRequest, _clientContext);
|
|
||||||
errorContext.SetError(Constants.Errors.UnsupportedResponseType);
|
|
||||||
await SendErrorRedirectAsync(_clientContext, errorContext);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var authResponseContext = new OAuthAuthorizationEndpointResponseContext(Context, Options, new AuthenticationTicket(signin.Principal, signin.Properties, signin.Identity.AuthenticationType), _authorizeEndpointRequest, null, code);
|
|
||||||
|
|
||||||
await Options.Provider.AuthorizationEndpointResponse(authResponseContext);
|
|
||||||
|
|
||||||
foreach (var parameter in authResponseContext.AdditionalResponseParameters)
|
|
||||||
{
|
|
||||||
returnParameter[parameter.Key] = parameter.Value.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
returnParameter[Constants.Parameters.Code] = code;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_authorizeEndpointRequest.State))
|
|
||||||
{
|
|
||||||
returnParameter[Constants.Parameters.State] = _authorizeEndpointRequest.State;
|
|
||||||
}
|
|
||||||
|
|
||||||
string location = string.Empty;
|
|
||||||
if (_authorizeEndpointRequest.IsFormPostResponseMode)
|
|
||||||
{
|
|
||||||
location = Options.FormPostEndpoint.ToString();
|
|
||||||
returnParameter[Constants.Parameters.RedirectUri] = _clientContext.RedirectUri;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
location = _clientContext.RedirectUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var key in returnParameter.Keys)
|
|
||||||
{
|
|
||||||
location = QueryHelpers.AddQueryString(location, key, returnParameter[key]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Response.Redirect(location);
|
|
||||||
}
|
|
||||||
else if (_authorizeEndpointRequest.IsImplicitGrantType)
|
|
||||||
{
|
|
||||||
string location = _clientContext.RedirectUri;
|
|
||||||
|
|
||||||
DateTimeOffset currentUtc = Options.SystemClock.UtcNow;
|
|
||||||
signin.Properties.IssuedUtc = currentUtc;
|
|
||||||
signin.Properties.ExpiresUtc = currentUtc.Add(Options.AccessTokenExpireTimeSpan);
|
|
||||||
|
|
||||||
// associate client_id with access token
|
|
||||||
signin.Properties.Items[Constants.Extra.ClientId] = _authorizeEndpointRequest.ClientId;
|
|
||||||
|
|
||||||
var accessTokenContext = new AuthenticationTokenCreateContext(Context, Options.AccessTokenFormat, new AuthenticationTicket(signin.Principal, signin.Properties, signin.Identity.AuthenticationType));
|
|
||||||
|
|
||||||
await Options.AccessTokenProvider.CreateAsync(accessTokenContext);
|
|
||||||
|
|
||||||
string accessToken = accessTokenContext.Token;
|
|
||||||
if (string.IsNullOrEmpty(accessToken))
|
|
||||||
{
|
|
||||||
accessToken = accessTokenContext.SerializeTicket();
|
|
||||||
}
|
|
||||||
|
|
||||||
DateTimeOffset? accessTokenExpiresUtc = accessTokenContext.Ticket.Properties.ExpiresUtc;
|
|
||||||
|
|
||||||
var appender = new Appender(location, '#');
|
|
||||||
|
|
||||||
appender.Append(Constants.Parameters.AccessToken, accessToken)
|
|
||||||
.Append(Constants.Parameters.TokenType, Constants.TokenTypes.Bearer);
|
|
||||||
|
|
||||||
if (accessTokenExpiresUtc.HasValue)
|
|
||||||
{
|
|
||||||
TimeSpan? expiresTimeSpan = accessTokenExpiresUtc - currentUtc;
|
|
||||||
var expiresIn = (long)(expiresTimeSpan.Value.TotalSeconds + .5);
|
|
||||||
appender.Append(Constants.Parameters.ExpiresIn, expiresIn.ToString(CultureInfo.InvariantCulture));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_authorizeEndpointRequest.State))
|
|
||||||
{
|
|
||||||
appender.Append(Constants.Parameters.State, _authorizeEndpointRequest.State);
|
|
||||||
}
|
|
||||||
|
|
||||||
var authResponseContext = new OAuthAuthorizationEndpointResponseContext(Context, Options, new AuthenticationTicket(signin.Principal, signin.Properties, signin.Identity.AuthenticationType), _authorizeEndpointRequest, accessToken, null);
|
|
||||||
|
|
||||||
await Options.Provider.AuthorizationEndpointResponse(authResponseContext);
|
|
||||||
|
|
||||||
foreach (var parameter in authResponseContext.AdditionalResponseParameters)
|
|
||||||
{
|
|
||||||
appender.Append(parameter.Key, parameter.Value.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
Response.Redirect(appender.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Builder;
|
|
||||||
using Microsoft.AspNet.DataProtection;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.WebEncoders;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Authorization Server middleware component which is added to an OWIN pipeline. This class is not
|
|
||||||
/// created by application code directly, instead it is added by calling the the IAppBuilder UseOAuthAuthorizationServer
|
|
||||||
/// extension method.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthAuthorizationServerMiddleware : AuthenticationMiddleware<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Authorization Server middleware component which is added to an OWIN pipeline. This constructor is not
|
|
||||||
/// called by application code directly, instead it is added by calling the the IAppBuilder UseOAuthAuthorizationServer
|
|
||||||
/// extension method.
|
|
||||||
/// </summary>
|
|
||||||
public OAuthAuthorizationServerMiddleware(RequestDelegate next, OAuthAuthorizationServerOptions options, ILoggerFactory loggerFactory, IDataProtectionProvider dataProtectionProvider, IUrlEncoder encoder) : base(next, options, loggerFactory, encoder)
|
|
||||||
{
|
|
||||||
if (Options.Provider == null)
|
|
||||||
{
|
|
||||||
Options.Provider = new OAuthAuthorizationServerProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Options.AuthorizationCodeFormat == null)
|
|
||||||
{
|
|
||||||
IDataProtector dataProtecter = dataProtectionProvider.CreateProtector(typeof(OAuthAuthorizationServerMiddleware).FullName, "Authentication_Code", "v1");
|
|
||||||
|
|
||||||
Options.AuthorizationCodeFormat = new TicketDataFormat(dataProtecter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Options.RefreshTokenFormat == null)
|
|
||||||
{
|
|
||||||
IDataProtector dataProtecter = dataProtectionProvider.CreateProtector(typeof(OAuthAuthorizationServerMiddleware).FullName, "Refresh_Token", "v1");
|
|
||||||
|
|
||||||
Options.RefreshTokenFormat = new TicketDataFormat(dataProtecter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Options.TokenDataProtector == null)
|
|
||||||
{
|
|
||||||
#if DNXCORE50
|
|
||||||
Options.TokenDataProtector = new DataProtectionProvider(new DirectoryInfo(Environment.GetEnvironmentVariable("Temp"))).CreateProtector("OAuth.AspNet.AuthServer");
|
|
||||||
#else
|
|
||||||
Options.TokenDataProtector = new MonoDataProtectionProvider("OAuth.AspNet.AuthServer").CreateProtector("OAuth.Data.Protector");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Options.AccessTokenFormat == null)
|
|
||||||
{
|
|
||||||
IDataProtector dataProtecter = Options.TokenDataProtector.CreateProtector("Access_Token", "v1");
|
|
||||||
|
|
||||||
Options.AccessTokenFormat = new TicketDataFormat(dataProtecter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Options.AuthorizationCodeProvider == null)
|
|
||||||
{
|
|
||||||
Options.AuthorizationCodeProvider = new AuthenticationTokenProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Options.AccessTokenProvider == null)
|
|
||||||
{
|
|
||||||
Options.AccessTokenProvider = new AuthenticationTokenProvider();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Options.RefreshTokenProvider == null)
|
|
||||||
{
|
|
||||||
Options.RefreshTokenProvider = new AuthenticationTokenProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called by the AuthenticationMiddleware base class to create a per-request handler.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>A new instance of the request handler</returns>
|
|
||||||
protected override AuthenticationHandler<OAuthAuthorizationServerOptions> CreateHandler()
|
|
||||||
{
|
|
||||||
return new OAuthAuthorizationServerHandler();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.DataProtection;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Options class provides information needed to control Authorization Server middleware behavior
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthAuthorizationServerOptions : AuthenticationOptions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an instance of authorization server options with default values.
|
|
||||||
/// </summary>
|
|
||||||
public OAuthAuthorizationServerOptions()
|
|
||||||
{
|
|
||||||
AuthenticationScheme = OAuthDefaults.AuthenticationType;
|
|
||||||
AuthorizationCodeExpireTimeSpan = TimeSpan.FromMinutes(5);
|
|
||||||
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20);
|
|
||||||
SystemClock = new SystemClock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The request path where client applications will redirect the user-agent in order to
|
|
||||||
/// obtain user consent to issue a token. Must begin with a leading slash, like "/Authorize".
|
|
||||||
/// </summary>
|
|
||||||
public PathString AuthorizeEndpointPath { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The request path client applications communicate with directly as part of the OAuth protocol.
|
|
||||||
/// Must begin with a leading slash, like "/Token". If the client is issued a client_secret, it must
|
|
||||||
/// be provided to this endpoint.
|
|
||||||
/// </summary>
|
|
||||||
public PathString TokenEndpointPath { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The object provided by the application to process events raised by the Authorization Server middleware.
|
|
||||||
/// The application may implement the interface fully, or it may create an instance of OAuthAuthorizationServerProvider
|
|
||||||
/// and assign delegates only to the events it wants to process.
|
|
||||||
/// </summary>
|
|
||||||
public IOAuthAuthorizationServerProvider Provider { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The data format used to protect and unprotect the information contained in the authorization code.
|
|
||||||
/// If not provided by the application the default data protection provider depends on the host server.
|
|
||||||
/// The SystemWeb host on IIS will use ASP.NET machine key data protection, and HttpListener and other self-hosted
|
|
||||||
/// servers will use DPAPI data protection.
|
|
||||||
/// </summary>
|
|
||||||
public ISecureDataFormat<AuthenticationTicket> AuthorizationCodeFormat { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The data protection provider used to protect token information.
|
|
||||||
/// </summary>
|
|
||||||
public IDataProtector TokenDataProtector { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The data format used to protect the information contained in the access token.
|
|
||||||
/// If not provided by the application the default data protection provider depends on the host server.
|
|
||||||
/// The SystemWeb host on IIS will use ASP.NET machine key data protection, and HttpListener and other self-hosted
|
|
||||||
/// servers will use DPAPI data protection. If a different access token
|
|
||||||
/// provider or format is assigned, a compatible instance must be assigned to the OAuthBearerAuthenticationOptions.AccessTokenProvider
|
|
||||||
/// or OAuthBearerAuthenticationOptions.AccessTokenFormat property of the resource server.
|
|
||||||
/// </summary>
|
|
||||||
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The data format used to protect and unprotect the information contained in the refresh token.
|
|
||||||
/// If not provided by the application the default data protection provider depends on the host server.
|
|
||||||
/// The SystemWeb host on IIS will use ASP.NET machine key data protection, and HttpListener and other self-hosted
|
|
||||||
/// servers will use DPAPI data protection.
|
|
||||||
/// </summary>
|
|
||||||
public ISecureDataFormat<AuthenticationTicket> RefreshTokenFormat { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The period of time the authorization code remains valid after being issued. The default is five minutes.
|
|
||||||
/// This time span must also take into account clock synchronization between servers in a web farm, so a very
|
|
||||||
/// brief value could result in unexpectedly expired tokens.
|
|
||||||
/// </summary>
|
|
||||||
public TimeSpan AuthorizationCodeExpireTimeSpan { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The period of time the access token remains valid after being issued. The default is twenty minutes.
|
|
||||||
/// The client application is expected to refresh or acquire a new access token after the token has expired.
|
|
||||||
/// </summary>
|
|
||||||
public TimeSpan AccessTokenExpireTimeSpan { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Produces a single-use authorization code to return to the client application. For the OAuth server to be secure the
|
|
||||||
/// application MUST provide an instance for AuthorizationCodeProvider where the token produced by the OnCreate or OnCreateAsync event
|
|
||||||
/// is considered valid for only one call to OnReceive or OnReceiveAsync.
|
|
||||||
/// </summary>
|
|
||||||
public IAuthenticationTokenProvider AuthorizationCodeProvider { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Produces a bearer token the client application will typically be providing to resource server as the authorization bearer
|
|
||||||
/// http request header. If not provided the token produced on the server's default data protection. If a different access token
|
|
||||||
/// provider or format is assigned, a compatible instance must be assigned to the OAuthBearerAuthenticationOptions.AccessTokenProvider
|
|
||||||
/// or OAuthBearerAuthenticationOptions.AccessTokenFormat property of the resource server.
|
|
||||||
/// </summary>
|
|
||||||
public IAuthenticationTokenProvider AccessTokenProvider { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Produces a refresh token which may be used to produce a new access token when needed. If not provided the authorization server will
|
|
||||||
/// not return refresh tokens from the /Token endpoint.
|
|
||||||
/// </summary>
|
|
||||||
public IAuthenticationTokenProvider RefreshTokenProvider { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set to true if the web application is able to render error messages on the /Authorize endpoint. This is only needed for cases where
|
|
||||||
/// the browser is not redirected back to the client application, for example, when the client_id or redirect_uri are incorrect. The
|
|
||||||
/// /Authorize endpoint should expect to see "oauth.Error", "oauth.ErrorDescription", "oauth.ErrorUri" properties added to the owin environment.
|
|
||||||
/// </summary>
|
|
||||||
public bool ApplicationCanDisplayErrors { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used to know what the current clock time is when calculating or validating token expiration. When not assigned default is based on
|
|
||||||
/// DateTimeOffset.UtcNow. This is typically needed only for unit testing.
|
|
||||||
/// </summary>
|
|
||||||
public ISystemClock SystemClock { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True to allow authorize and token requests to arrive on http URI addresses, and to allow incoming
|
|
||||||
/// redirect_uri authorize request parameter to have http URI addresses.
|
|
||||||
/// </summary>
|
|
||||||
public bool AllowInsecureHttp { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Endpoint responsible for Form Post Response Mode
|
|
||||||
/// See also, http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html
|
|
||||||
/// </summary>
|
|
||||||
public PathString FormPostEndpoint { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,378 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Default implementation of IOAuthAuthorizationServerProvider used by Authorization
|
|
||||||
/// Server to communicate with the web application while processing requests. OAuthAuthorizationServerProvider provides some default behavior,
|
|
||||||
/// may be used as a virtual base class, and offers delegate properties which may be used to
|
|
||||||
/// handle individual calls without declaring a new class type.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthAuthorizationServerProvider : IOAuthAuthorizationServerProvider
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Creates new instance of default provider behavior
|
|
||||||
/// </summary>
|
|
||||||
public OAuthAuthorizationServerProvider()
|
|
||||||
{
|
|
||||||
OnMatchEndpoint = context => Task.FromResult<object>(null);
|
|
||||||
OnValidateClientRedirectUri = context => Task.FromResult<object>(null);
|
|
||||||
OnValidateClientAuthentication = context => Task.FromResult<object>(null);
|
|
||||||
|
|
||||||
OnValidateAuthorizeRequest = DefaultBehavior.ValidateAuthorizeRequest;
|
|
||||||
OnValidateTokenRequest = DefaultBehavior.ValidateTokenRequest;
|
|
||||||
|
|
||||||
OnGrantAuthorizationCode = DefaultBehavior.GrantAuthorizationCode;
|
|
||||||
OnGrantResourceOwnerCredentials = context => Task.FromResult<object>(null);
|
|
||||||
OnGrantRefreshToken = DefaultBehavior.GrantRefreshToken;
|
|
||||||
OnGrantClientCredentials = context => Task.FromResult<object>(null);
|
|
||||||
OnGrantCustomExtension = context => Task.FromResult<object>(null);
|
|
||||||
|
|
||||||
OnAuthorizeEndpoint = context => Task.FromResult<object>(null);
|
|
||||||
OnTokenEndpoint = context => Task.FromResult<object>(null);
|
|
||||||
|
|
||||||
OnAuthorizationEndpointResponse = context => Task.FromResult<object>(null);
|
|
||||||
|
|
||||||
OnTokenEndpointResponse = context => Task.FromResult<object>(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to determine if an incoming request is treated as an Authorize or Token
|
|
||||||
/// endpoint. If Options.AuthorizeEndpointPath or Options.TokenEndpointPath
|
|
||||||
/// are assigned values, then handling this event is optional and context.IsAuthorizeEndpoint and context.IsTokenEndpoint
|
|
||||||
/// will already be true if the request path matches.
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthMatchContext, Task> OnMatchEndpoint { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to validate that the context.ClientId is a registered "client_id", and that the context.RedirectUri a "redirect_uri"
|
|
||||||
/// registered for that client. This only occurs when processing the Authorize endpoint. The application MUST implement this
|
|
||||||
/// call, and it MUST validate both of those factors before calling context.Validated. If the context.Validated method is called
|
|
||||||
/// with a given redirectUri parameter, then IsValidated will only become true if the incoming redirect URI matches the given redirect URI.
|
|
||||||
/// If context.Validated is not called the request will not proceed further.
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthValidateClientRedirectUriContext, Task> OnValidateClientRedirectUri { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to validate that the origin of the request is a registered "client_id", and that the correct credentials for that client are
|
|
||||||
/// present on the request. If the web application accepts Basic authentication credentials,
|
|
||||||
/// context.TryGetBasicCredentials(out clientId, out clientSecret) may be called to acquire those values if present in the request header. If the web
|
|
||||||
/// application accepts "client_id" and "client_secret" as form encoded POST parameters,
|
|
||||||
/// context.TryGetFormCredentials(out clientId, out clientSecret) may be called to acquire those values if present in the request body.
|
|
||||||
/// If context.Validated is not called the request will not proceed further.
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthValidateClientAuthenticationContext, Task> OnValidateClientAuthentication { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called for each request to the Authorize endpoint to determine if the request is valid and should continue.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to assume well-formed requests, with
|
|
||||||
/// validated client redirect URI, should continue processing. An application may add any additional constraints.
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthValidateAuthorizeRequestContext, Task> OnValidateAuthorizeRequest { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called for each request to the Token endpoint to determine if the request is valid and should continue.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to assume well-formed requests, with
|
|
||||||
/// validated client credentials, should continue processing. An application may add any additional constraints.
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthValidateTokenRequestContext, Task> OnValidateTokenRequest { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "authorization_code". This occurs after the Authorize
|
|
||||||
/// endpoint as redirected the user-agent back to the client with a "code" parameter, and the client is exchanging that for an "access_token".
|
|
||||||
/// The claims and properties
|
|
||||||
/// associated with the authorization code are present in the context.Ticket. The application must call context.Validated to instruct the Authorization
|
|
||||||
/// Server middleware to issue an access token based on those claims and properties. The call to context.Validated may be given a different
|
|
||||||
/// AuthenticationTicket or ClaimsIdentity in order to control which information flows from authorization code to access token.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to flow information from the authorization code to
|
|
||||||
/// the access token unmodified.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.1.3
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthGrantAuthorizationCodeContext, Task> OnGrantAuthorizationCode { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "password". This occurs when the user has provided name and password
|
|
||||||
/// credentials directly into the client application's user interface, and the client application is using those to acquire an "access_token" and
|
|
||||||
/// optional "refresh_token". If the web application supports the
|
|
||||||
/// resource owner credentials grant type it must validate the context.Username and context.Password as appropriate. To issue an
|
|
||||||
/// access token the context.Validated must be called with a new ticket containing the claims about the resource owner which should be associated
|
|
||||||
/// with the access token. The application should take appropriate measures to ensure that the endpoint isn’t abused by malicious callers.
|
|
||||||
/// The default behavior is to reject this grant type.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.3.2
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthGrantResourceOwnerCredentialsContext, Task> OnGrantResourceOwnerCredentials { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "client_credentials". This occurs when a registered client
|
|
||||||
/// application wishes to acquire an "access_token" to interact with protected resources on it's own behalf, rather than on behalf of an authenticated user.
|
|
||||||
/// If the web application supports the client credentials it may assume the context.ClientId has been validated by the ValidateClientAuthentication call.
|
|
||||||
/// To issue an access token the context.Validated must be called with a new ticket containing the claims about the client application which should be associated
|
|
||||||
/// with the access token. The application should take appropriate measures to ensure that the endpoint isn’t abused by malicious callers.
|
|
||||||
/// The default behavior is to reject this grant type.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.4.2
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthGrantClientCredentialsContext, Task> OnGrantClientCredentials { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "refresh_token". This occurs if your application has issued a "refresh_token"
|
|
||||||
/// along with the "access_token", and the client is attempting to use the "refresh_token" to acquire a new "access_token", and possibly a new "refresh_token".
|
|
||||||
/// To issue a refresh token the an Options.RefreshTokenProvider must be assigned to create the value which is returned. The claims and properties
|
|
||||||
/// associated with the refresh token are present in the context.Ticket. The application must call context.Validated to instruct the
|
|
||||||
/// Authorization Server middleware to issue an access token based on those claims and properties. The call to context.Validated may
|
|
||||||
/// be given a different AuthenticationTicket or ClaimsIdentity in order to control which information flows from the refresh token to
|
|
||||||
/// the access token. The default behavior when using the OAuthAuthorizationServerProvider is to flow information from the refresh token to
|
|
||||||
/// the access token unmodified.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-6
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthGrantRefreshTokenContext, Task> OnGrantRefreshToken { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token andpoint arrives with a "grant_type" of any other value. If the application supports custom grant types
|
|
||||||
/// it is entirely responsible for determining if the request should result in an access_token. If context.Validated is called with ticket
|
|
||||||
/// information the response body is produced in the same way as the other standard grant types. If additional response parameters must be
|
|
||||||
/// included they may be added in the final TokenEndpoint call.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.5
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthGrantCustomExtensionContext, Task> OnGrantCustomExtension { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called at the final stage of an incoming Authorize endpoint request before the execution continues on to the web application component
|
|
||||||
/// responsible for producing the html response. Anything present in the OWIN pipeline following the Authorization Server may produce the
|
|
||||||
/// response for the Authorize page. If running on IIS any ASP.NET technology running on the server may produce the response for the
|
|
||||||
/// Authorize page. If the web application wishes to produce the response directly in the AuthorizeEndpoint call it may write to the
|
|
||||||
/// context.Response directly and should call context.RequestCompleted to stop other handlers from executing. If the web application wishes
|
|
||||||
/// to grant the authorization directly in the AuthorizeEndpoint call it cay call context.OwinContext.Authentication.SignIn with the
|
|
||||||
/// appropriate ClaimsIdentity and should call context.RequestCompleted to stop other handlers from executing.
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthAuthorizeEndpointContext, Task> OnAuthorizeEndpoint { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called at the final stage of a successful Token endpoint request. An application may implement this call in order to do any final
|
|
||||||
/// modification of the claims being used to issue access or refresh tokens. This call may also be used in order to add additional
|
|
||||||
/// response parameters to the Token endpoint's json response body.
|
|
||||||
/// </summary>
|
|
||||||
public Func<OAuthTokenEndpointContext, Task> OnTokenEndpoint { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called before the AuthorizationEndpoint redirects its response to the caller. The response could be the
|
|
||||||
/// token, when using implicit flow or the AuthorizationEndpoint when using authorization code flow.
|
|
||||||
/// An application may implement this call in order to do any final modification of the claims being used
|
|
||||||
/// to issue access or refresh tokens. This call may also be used in order to add additional
|
|
||||||
/// response parameters to the authorization endpoint's response.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public Func<OAuthAuthorizationEndpointResponseContext, Task> OnAuthorizationEndpointResponse { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called before the TokenEndpoint redirects its response to the caller.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public Func<OAuthTokenEndpointResponseContext, Task> OnTokenEndpointResponse { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to determine if an incoming request is treated as an Authorize or Token
|
|
||||||
/// endpoint. If Options.AuthorizeEndpointPath or Options.TokenEndpointPath
|
|
||||||
/// are assigned values, then handling this event is optional and context.IsAuthorizeEndpoint and context.IsTokenEndpoint
|
|
||||||
/// will already be true if the request path matches.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task MatchEndpoint(OAuthMatchContext context)
|
|
||||||
{
|
|
||||||
return OnMatchEndpoint.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to validate that the context.ClientId is a registered "client_id", and that the context.RedirectUri a "redirect_uri"
|
|
||||||
/// registered for that client. This only occurs when processing the Authorize endpoint. The application MUST implement this
|
|
||||||
/// call, and it MUST validate both of those factors before calling context.Validated. If the context.Validated method is called
|
|
||||||
/// with a given redirectUri parameter, then IsValidated will only become true if the incoming redirect URI matches the given redirect URI.
|
|
||||||
/// If context.Validated is not called the request will not proceed further.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
|
|
||||||
{
|
|
||||||
return OnValidateClientRedirectUri.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called to validate that the origin of the request is a registered "client_id", and that the correct credentials for that client are
|
|
||||||
/// present on the request. If the web application accepts Basic authentication credentials,
|
|
||||||
/// context.TryGetBasicCredentials(out clientId, out clientSecret) may be called to acquire those values if present in the request header. If the web
|
|
||||||
/// application accepts "client_id" and "client_secret" as form encoded POST parameters,
|
|
||||||
/// context.TryGetFormCredentials(out clientId, out clientSecret) may be called to acquire those values if present in the request body.
|
|
||||||
/// If context.Validated is not called the request will not proceed further.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
|
|
||||||
{
|
|
||||||
return OnValidateClientAuthentication.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called for each request to the Authorize endpoint to determine if the request is valid and should continue.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to assume well-formed requests, with
|
|
||||||
/// validated client redirect URI, should continue processing. An application may add any additional constraints.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task ValidateAuthorizeRequest(OAuthValidateAuthorizeRequestContext context)
|
|
||||||
{
|
|
||||||
return OnValidateAuthorizeRequest.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called for each request to the Token endpoint to determine if the request is valid and should continue.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to assume well-formed requests, with
|
|
||||||
/// validated client credentials, should continue processing. An application may add any additional constraints.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task ValidateTokenRequest(OAuthValidateTokenRequestContext context)
|
|
||||||
{
|
|
||||||
return OnValidateTokenRequest.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "authorization_code". This occurs after the Authorize
|
|
||||||
/// endpoint as redirected the user-agent back to the client with a "code" parameter, and the client is exchanging that for an "access_token".
|
|
||||||
/// The claims and properties
|
|
||||||
/// associated with the authorization code are present in the context.Ticket. The application must call context.Validated to instruct the Authorization
|
|
||||||
/// Server middleware to issue an access token based on those claims and properties. The call to context.Validated may be given a different
|
|
||||||
/// AuthenticationTicket or ClaimsIdentity in order to control which information flows from authorization code to access token.
|
|
||||||
/// The default behavior when using the OAuthAuthorizationServerProvider is to flow information from the authorization code to
|
|
||||||
/// the access token unmodified.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.1.3
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task GrantAuthorizationCode(OAuthGrantAuthorizationCodeContext context)
|
|
||||||
{
|
|
||||||
return OnGrantAuthorizationCode.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "refresh_token". This occurs if your application has issued a "refresh_token"
|
|
||||||
/// along with the "access_token", and the client is attempting to use the "refresh_token" to acquire a new "access_token", and possibly a new "refresh_token".
|
|
||||||
/// To issue a refresh token the an Options.RefreshTokenProvider must be assigned to create the value which is returned. The claims and properties
|
|
||||||
/// associated with the refresh token are present in the context.Ticket. The application must call context.Validated to instruct the
|
|
||||||
/// Authorization Server middleware to issue an access token based on those claims and properties. The call to context.Validated may
|
|
||||||
/// be given a different AuthenticationTicket or ClaimsIdentity in order to control which information flows from the refresh token to
|
|
||||||
/// the access token. The default behavior when using the OAuthAuthorizationServerProvider is to flow information from the refresh token to
|
|
||||||
/// the access token unmodified.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-6
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
|
|
||||||
{
|
|
||||||
return OnGrantRefreshToken.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "password". This occurs when the user has provided name and password
|
|
||||||
/// credentials directly into the client application's user interface, and the client application is using those to acquire an "access_token" and
|
|
||||||
/// optional "refresh_token". If the web application supports the
|
|
||||||
/// resource owner credentials grant type it must validate the context.Username and context.Password as appropriate. To issue an
|
|
||||||
/// access token the context.Validated must be called with a new ticket containing the claims about the resource owner which should be associated
|
|
||||||
/// with the access token. The application should take appropriate measures to ensure that the endpoint isn’t abused by malicious callers.
|
|
||||||
/// The default behavior is to reject this grant type.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.3.2
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
|
|
||||||
{
|
|
||||||
return OnGrantResourceOwnerCredentials.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of "client_credentials". This occurs when a registered client
|
|
||||||
/// application wishes to acquire an "access_token" to interact with protected resources on it's own behalf, rather than on behalf of an authenticated user.
|
|
||||||
/// If the web application supports the client credentials it may assume the context.ClientId has been validated by the ValidateClientAuthentication call.
|
|
||||||
/// To issue an access token the context.Validated must be called with a new ticket containing the claims about the client application which should be associated
|
|
||||||
/// with the access token. The application should take appropriate measures to ensure that the endpoint isn’t abused by malicious callers.
|
|
||||||
/// The default behavior is to reject this grant type.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.4.2
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
|
|
||||||
{
|
|
||||||
return OnGrantClientCredentials.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called when a request to the Token endpoint arrives with a "grant_type" of any other value. If the application supports custom grant types
|
|
||||||
/// it is entirely responsible for determining if the request should result in an access_token. If context.Validated is called with ticket
|
|
||||||
/// information the response body is produced in the same way as the other standard grant types. If additional response parameters must be
|
|
||||||
/// included they may be added in the final TokenEndpoint call.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.5
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task GrantCustomExtension(OAuthGrantCustomExtensionContext context)
|
|
||||||
{
|
|
||||||
return OnGrantCustomExtension.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called at the final stage of an incoming Authorize endpoint request before the execution continues on to the web application component
|
|
||||||
/// responsible for producing the html response. Anything present in the OWIN pipeline following the Authorization Server may produce the
|
|
||||||
/// response for the Authorize page. If running on IIS any ASP.NET technology running on the server may produce the response for the
|
|
||||||
/// Authorize page. If the web application wishes to produce the response directly in the AuthorizeEndpoint call it may write to the
|
|
||||||
/// context.Response directly and should call context.RequestCompleted to stop other handlers from executing. If the web application wishes
|
|
||||||
/// to grant the authorization directly in the AuthorizeEndpoint call it cay call context.OwinContext.Authentication.SignIn with the
|
|
||||||
/// appropriate ClaimsIdentity and should call context.RequestCompleted to stop other handlers from executing.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task AuthorizeEndpoint(OAuthAuthorizeEndpointContext context)
|
|
||||||
{
|
|
||||||
return OnAuthorizeEndpoint.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called at the final stage of a successful Token endpoint request. An application may implement this call in order to do any final
|
|
||||||
/// modification of the claims being used to issue access or refresh tokens. This call may also be used in order to add additional
|
|
||||||
/// response parameters to the Token endpoint's json response body.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task TokenEndpoint(OAuthTokenEndpointContext context)
|
|
||||||
{
|
|
||||||
return OnTokenEndpoint.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called before the AuthorizationEndpoint redirects its response to the caller. The response could be the
|
|
||||||
/// token, when using implicit flow or the AuthorizationEndpoint when using authorization code flow.
|
|
||||||
/// An application may implement this call in order to do any final modification of the claims being used
|
|
||||||
/// to issue access or refresh tokens. This call may also be used in order to add additional
|
|
||||||
/// response parameters to the authorization endpoint's response.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">The context of the event carries information in and results out.</param>
|
|
||||||
/// <returns>Task to enable asynchronous execution</returns>
|
|
||||||
public virtual Task AuthorizationEndpointResponse(OAuthAuthorizationEndpointResponseContext context)
|
|
||||||
{
|
|
||||||
return OnAuthorizationEndpointResponse.Invoke(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called before the TokenEndpoint redirects its response to the caller.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public virtual Task TokenEndpointResponse(OAuthTokenEndpointResponseContext context)
|
|
||||||
{
|
|
||||||
return OnTokenEndpointResponse.Invoke(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An event raised after the Authorization Server has processed the request, but before it is passed on to the web application.
|
|
||||||
/// Calling RequestCompleted will prevent the request from passing on to the web application.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthAuthorizeEndpointContext : BaseOAuthEndpointContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an instance of this context
|
|
||||||
/// </summary>
|
|
||||||
public OAuthAuthorizeEndpointContext(HttpContext context, OAuthAuthorizationServerOptions options, AuthorizeEndpointRequest authorizeRequest) : base(context, options)
|
|
||||||
{
|
|
||||||
AuthorizeRequest = authorizeRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets OAuth authorization request data.
|
|
||||||
/// </summary>
|
|
||||||
public AuthorizeEndpointRequest AuthorizeRequest { get; private set; }
|
|
||||||
|
|
||||||
public bool IsRequestCompleted { get; private set; }
|
|
||||||
|
|
||||||
public void RequestCompleted()
|
|
||||||
{
|
|
||||||
IsRequestCompleted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Microsoft.AspNet.Http.Authentication;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information when processing an Authorization Response
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthAuthorizationEndpointResponseContext : BaseOAuthEndpointContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthAuthorizationEndpointResponseContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="ticket"></param>
|
|
||||||
/// <param name="tokenEndpointRequest"></param>
|
|
||||||
public OAuthAuthorizationEndpointResponseContext(HttpContext context, OAuthAuthorizationServerOptions options, AuthenticationTicket ticket, AuthorizeEndpointRequest authorizeEndpointRequest, string accessToken, string authorizationCode) : base(context, options)
|
|
||||||
{
|
|
||||||
if (ticket == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("ticket");
|
|
||||||
}
|
|
||||||
|
|
||||||
Principal = ticket.Principal;
|
|
||||||
Properties = ticket.Properties;
|
|
||||||
AuthorizeEndpointRequest = authorizeEndpointRequest;
|
|
||||||
AdditionalResponseParameters = new Dictionary<string, object>(StringComparer.Ordinal);
|
|
||||||
AccessToken = accessToken;
|
|
||||||
AuthorizationCode = authorizationCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the identity of the resource owner.
|
|
||||||
/// </summary>
|
|
||||||
public ClaimsPrincipal Principal { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary containing the state of the authentication session.
|
|
||||||
/// </summary>
|
|
||||||
public AuthenticationProperties Properties { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets information about the authorize endpoint request.
|
|
||||||
/// </summary>
|
|
||||||
public AuthorizeEndpointRequest AuthorizeEndpointRequest { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enables additional values to be appended to the token response.
|
|
||||||
/// </summary>
|
|
||||||
public IDictionary<string, object> AdditionalResponseParameters { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The serialized Access-Token. Depending on the flow, it can be null.
|
|
||||||
/// </summary>
|
|
||||||
public string AccessToken { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The created Authorization-Code. Depending on the flow, it can be null.
|
|
||||||
/// </summary>
|
|
||||||
public string AuthorizationCode { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
public static class Constants
|
|
||||||
{
|
|
||||||
public static class Parameters
|
|
||||||
{
|
|
||||||
public const string ResponseType = "response_type";
|
|
||||||
public const string GrantType = "grant_type";
|
|
||||||
public const string ClientId = "client_id";
|
|
||||||
public const string ClientSecret = "client_secret";
|
|
||||||
public const string RedirectUri = "redirect_uri";
|
|
||||||
public const string Scope = "scope";
|
|
||||||
public const string State = "state";
|
|
||||||
public const string Code = "code";
|
|
||||||
public const string RefreshToken = "refresh_token";
|
|
||||||
public const string Username = "username";
|
|
||||||
public const string Password = "password";
|
|
||||||
public const string Error = "error";
|
|
||||||
public const string ErrorDescription = "error_description";
|
|
||||||
public const string ErrorUri = "error_uri";
|
|
||||||
public const string ExpiresIn = "expires_in";
|
|
||||||
public const string AccessToken = "access_token";
|
|
||||||
public const string TokenType = "token_type";
|
|
||||||
|
|
||||||
public const string ResponseMode = "response_mode";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ResponseTypes
|
|
||||||
{
|
|
||||||
public const string Code = "code";
|
|
||||||
public const string Token = "token";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class GrantTypes
|
|
||||||
{
|
|
||||||
public const string AuthorizationCode = "authorization_code";
|
|
||||||
public const string ClientCredentials = "client_credentials";
|
|
||||||
public const string RefreshToken = "refresh_token";
|
|
||||||
public const string Password = "password";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TokenTypes
|
|
||||||
{
|
|
||||||
public const string Bearer = "bearer";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Errors
|
|
||||||
{
|
|
||||||
public const string InvalidRequest = "invalid_request";
|
|
||||||
public const string InvalidClient = "invalid_client";
|
|
||||||
public const string InvalidGrant = "invalid_grant";
|
|
||||||
public const string UnsupportedResponseType = "unsupported_response_type";
|
|
||||||
public const string UnsupportedGrantType = "unsupported_grant_type";
|
|
||||||
public const string UnauthorizedClient = "unauthorized_client";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Extra
|
|
||||||
{
|
|
||||||
public const string ClientId = "client_id";
|
|
||||||
public const string RedirectUri = "redirect_uri";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ResponseModes
|
|
||||||
{
|
|
||||||
public const string FormPost = "form_post";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Default values used by authorization server and bearer authentication.
|
|
||||||
/// </summary>
|
|
||||||
public static class OAuthDefaults
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Default value for AuthenticationType property in the OAuthBearerAuthenticationOptions and
|
|
||||||
/// OAuthAuthorizationServerOptions.
|
|
||||||
/// </summary>
|
|
||||||
public const string AuthenticationType = "Bearer";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information when handling an OAuth authorization code grant.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthGrantAuthorizationCodeContext : BaseValidatingTicketContext<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthGrantAuthorizationCodeContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="ticket"></param>
|
|
||||||
public OAuthGrantAuthorizationCodeContext(HttpContext context, OAuthAuthorizationServerOptions options, AuthenticationTicket ticket) : base(context, options, ticket) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information used in handling an OAuth client credentials grant.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthGrantClientCredentialsContext : BaseValidatingTicketContext<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthGrantClientCredentialsContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="clientId"></param>
|
|
||||||
/// <param name="scope"></param>
|
|
||||||
public OAuthGrantClientCredentialsContext(HttpContext context, OAuthAuthorizationServerOptions options, string clientId, IList<string> scope) : base(context, options, null)
|
|
||||||
{
|
|
||||||
ClientId = clientId;
|
|
||||||
Scope = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// OAuth client id.
|
|
||||||
/// </summary>
|
|
||||||
public string ClientId { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of scopes allowed by the resource owner.
|
|
||||||
/// </summary>
|
|
||||||
public IList<string> Scope { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information used when handling OAuth extension grant types.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthGrantCustomExtensionContext : BaseValidatingTicketContext<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthGrantCustomExtensionContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="clientId"></param>
|
|
||||||
/// <param name="grantType"></param>
|
|
||||||
/// <param name="parameters"></param>
|
|
||||||
public OAuthGrantCustomExtensionContext(HttpContext context, OAuthAuthorizationServerOptions options, string clientId, string grantType, IReadableStringCollection parameters) : base(context, options, null)
|
|
||||||
{
|
|
||||||
ClientId = clientId;
|
|
||||||
GrantType = grantType;
|
|
||||||
Parameters = parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the OAuth client id.
|
|
||||||
/// </summary>
|
|
||||||
public string ClientId { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the OAuth extension grant type.
|
|
||||||
/// </summary>
|
|
||||||
public string GrantType { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a list of additional parameters from the token request.
|
|
||||||
/// </summary>
|
|
||||||
public IReadableStringCollection Parameters { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information used when granting an OAuth refresh token.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthGrantRefreshTokenContext : BaseValidatingTicketContext<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthGrantRefreshTokenContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="ticket"></param>
|
|
||||||
/// <param name="clientId"></param>
|
|
||||||
public OAuthGrantRefreshTokenContext(HttpContext context, OAuthAuthorizationServerOptions options, AuthenticationTicket ticket, string clientId) : base(context, options, ticket)
|
|
||||||
{
|
|
||||||
ClientId = clientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The OAuth client id.
|
|
||||||
/// </summary>
|
|
||||||
public string ClientId { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information used in handling an OAuth resource owner grant.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthGrantResourceOwnerCredentialsContext : BaseValidatingTicketContext<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthGrantResourceOwnerCredentialsContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="clientId"></param>
|
|
||||||
/// <param name="userName"></param>
|
|
||||||
/// <param name="password"></param>
|
|
||||||
/// <param name="scope"></param>
|
|
||||||
public OAuthGrantResourceOwnerCredentialsContext(HttpContext context, OAuthAuthorizationServerOptions options, string clientId, string userName, string password, IList<string> scope) : base(context, options, null)
|
|
||||||
{
|
|
||||||
ClientId = clientId;
|
|
||||||
UserName = userName;
|
|
||||||
Password = password;
|
|
||||||
Scope = scope;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// OAuth client id.
|
|
||||||
/// </summary>
|
|
||||||
public string ClientId { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resource owner username.
|
|
||||||
/// </summary>
|
|
||||||
public string UserName { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Resource owner password.
|
|
||||||
/// </summary>
|
|
||||||
public string Password { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of scopes allowed by the resource owner.
|
|
||||||
/// </summary>
|
|
||||||
public IList<string> Scope { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides notification used for determining the OAuth flow type based on the request.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthMatchContext : BaseControlContext
|
|
||||||
{
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthMatchContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
public OAuthMatchContext(HttpContext context, OAuthAuthorizationServerOptions options) : base(context)
|
|
||||||
{
|
|
||||||
if (options == null)
|
|
||||||
throw new ArgumentNullException(nameof(options));
|
|
||||||
|
|
||||||
Options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Members
|
|
||||||
|
|
||||||
public OAuthAuthorizationServerOptions Options { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether or not the endpoint is an OAuth authorize endpoint.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsAuthorizeEndpoint { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether or not the endpoint is an OAuth token endpoint.
|
|
||||||
/// </summary>
|
|
||||||
public bool IsTokenEndpoint { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the endpoint type to authorize endpoint.
|
|
||||||
/// </summary>
|
|
||||||
public void MatchesAuthorizeEndpoint()
|
|
||||||
{
|
|
||||||
IsAuthorizeEndpoint = true;
|
|
||||||
IsTokenEndpoint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the endpoint type to token endpoint.
|
|
||||||
/// </summary>
|
|
||||||
public void MatchesTokenEndpoint()
|
|
||||||
{
|
|
||||||
IsAuthorizeEndpoint = false;
|
|
||||||
IsTokenEndpoint = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the endpoint type to neither authorize nor token.
|
|
||||||
/// </summary>
|
|
||||||
public void MatchesNothing()
|
|
||||||
{
|
|
||||||
IsAuthorizeEndpoint = false;
|
|
||||||
IsTokenEndpoint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Microsoft.AspNet.Http.Authentication;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information used when processing an OAuth token request.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthTokenEndpointContext : BaseOAuthEndpointContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthTokenEndpointContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="ticket"></param>
|
|
||||||
/// <param name="tokenEndpointRequest"></param>
|
|
||||||
public OAuthTokenEndpointContext(HttpContext context, OAuthAuthorizationServerOptions options, AuthenticationTicket ticket, TokenEndpointRequest tokenEndpointRequest) : base(context, options)
|
|
||||||
{
|
|
||||||
if (ticket == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("ticket");
|
|
||||||
}
|
|
||||||
|
|
||||||
Principal = ticket.Principal;
|
|
||||||
Properties = ticket.Properties;
|
|
||||||
TokenEndpointRequest = tokenEndpointRequest;
|
|
||||||
AdditionalResponseParameters = new Dictionary<string, object>(StringComparer.Ordinal);
|
|
||||||
TokenIssued = Principal != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the identity of the resource owner.
|
|
||||||
/// </summary>
|
|
||||||
public ClaimsPrincipal Principal { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary containing the state of the authentication session.
|
|
||||||
/// </summary>
|
|
||||||
public AuthenticationProperties Properties { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets information about the token endpoint request.
|
|
||||||
/// </summary>
|
|
||||||
public TokenEndpointRequest TokenEndpointRequest { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether or not the token should be issued.
|
|
||||||
/// </summary>
|
|
||||||
public bool TokenIssued { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enables additional values to be appended to the token response.
|
|
||||||
/// </summary>
|
|
||||||
public IDictionary<string, object> AdditionalResponseParameters { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Issues the token.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="principal"></param>
|
|
||||||
/// <param name="properties"></param>
|
|
||||||
public void Issue(ClaimsPrincipal principal, AuthenticationProperties properties)
|
|
||||||
{
|
|
||||||
Principal = principal;
|
|
||||||
Properties = properties;
|
|
||||||
TokenIssued = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Microsoft.AspNet.Http.Authentication;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information used at the end of a token-endpoint-request.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthTokenEndpointResponseContext : BaseOAuthEndpointContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthTokenEndpointResponseContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="ticket"></param>
|
|
||||||
/// <param name="tokenEndpointRequest"></param>
|
|
||||||
public OAuthTokenEndpointResponseContext(HttpContext context, OAuthAuthorizationServerOptions options, AuthenticationTicket ticket, TokenEndpointRequest tokenEndpointRequest, string accessToken, IDictionary<string, object> additionalResponseParameters) : base(context, options)
|
|
||||||
{
|
|
||||||
if (ticket == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("ticket");
|
|
||||||
}
|
|
||||||
|
|
||||||
Principal = ticket.Principal;
|
|
||||||
Properties = ticket.Properties;
|
|
||||||
TokenEndpointRequest = tokenEndpointRequest;
|
|
||||||
AdditionalResponseParameters = new Dictionary<string, object>(StringComparer.Ordinal);
|
|
||||||
TokenIssued = Principal != null;
|
|
||||||
AccessToken = accessToken;
|
|
||||||
AdditionalResponseParameters = additionalResponseParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the identity of the resource owner.
|
|
||||||
/// </summary>
|
|
||||||
public ClaimsPrincipal Principal { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary containing the state of the authentication session.
|
|
||||||
/// </summary>
|
|
||||||
public AuthenticationProperties Properties { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The issued Access-Token
|
|
||||||
/// </summary>
|
|
||||||
public string AccessToken { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets information about the token endpoint request.
|
|
||||||
/// </summary>
|
|
||||||
public TokenEndpointRequest TokenEndpointRequest { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets whether or not the token should be issued.
|
|
||||||
/// </summary>
|
|
||||||
public bool TokenIssued { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enables additional values to be appended to the token response.
|
|
||||||
/// </summary>
|
|
||||||
public IDictionary<string, object> AdditionalResponseParameters { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Issues the token.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="principal"></param>
|
|
||||||
/// <param name="properties"></param>
|
|
||||||
public void Issue(ClaimsPrincipal principal, AuthenticationProperties properties)
|
|
||||||
{
|
|
||||||
Principal = principal;
|
|
||||||
Properties = properties;
|
|
||||||
TokenIssued = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information used in validating an OAuth authorization request.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthValidateAuthorizeRequestContext : BaseValidatingContext<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthValidateAuthorizeRequestContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="authorizeRequest"></param>
|
|
||||||
/// <param name="clientContext"></param>
|
|
||||||
public OAuthValidateAuthorizeRequestContext(HttpContext context, OAuthAuthorizationServerOptions options, AuthorizeEndpointRequest authorizeRequest, OAuthValidateClientRedirectUriContext clientContext) : base(context, options)
|
|
||||||
{
|
|
||||||
AuthorizeRequest = authorizeRequest;
|
|
||||||
ClientContext = clientContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets OAuth authorization request data.
|
|
||||||
/// </summary>
|
|
||||||
public AuthorizeEndpointRequest AuthorizeRequest { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets data about the OAuth client.
|
|
||||||
/// </summary>
|
|
||||||
public OAuthValidateClientRedirectUriContext ClientContext { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains information about the client credentials.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthValidateClientAuthenticationContext : BaseValidatingClientContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthValidateClientAuthenticationContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="parameters"></param>
|
|
||||||
public OAuthValidateClientAuthenticationContext(HttpContext context, OAuthAuthorizationServerOptions options, IReadableStringCollection parameters) : base(context, options, null)
|
|
||||||
{
|
|
||||||
Parameters = parameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the set of form parameters from the request.
|
|
||||||
/// </summary>
|
|
||||||
public IReadableStringCollection Parameters { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the client id and marks the context as validated by the application.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="clientId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool Validated(string clientId)
|
|
||||||
{
|
|
||||||
ClientId = clientId;
|
|
||||||
|
|
||||||
return Validated();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extracts HTTP basic authentication credentials from the HTTP authenticate header.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="clientId"></param>
|
|
||||||
/// <param name="clientSecret"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "Optimized for usage")]
|
|
||||||
public bool TryGetBasicCredentials(out string clientId, out string clientSecret)
|
|
||||||
{
|
|
||||||
// Client Authentication http://tools.ietf.org/html/rfc6749#section-2.3
|
|
||||||
// Client Authentication Password http://tools.ietf.org/html/rfc6749#section-2.3.1
|
|
||||||
string authorization = Request.Headers["Authorization"];
|
|
||||||
if (!string.IsNullOrWhiteSpace(authorization) && authorization.StartsWith("Basic ", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
byte[] data = Convert.FromBase64String(authorization.Substring("Basic ".Length).Trim());
|
|
||||||
string text = Encoding.UTF8.GetString(data);
|
|
||||||
int delimiterIndex = text.IndexOf(':');
|
|
||||||
if (delimiterIndex >= 0)
|
|
||||||
{
|
|
||||||
clientId = text.Substring(0, delimiterIndex);
|
|
||||||
clientSecret = text.Substring(delimiterIndex + 1);
|
|
||||||
ClientId = clientId;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (FormatException)
|
|
||||||
{
|
|
||||||
// Bad Base64 string
|
|
||||||
}
|
|
||||||
catch (ArgumentException)
|
|
||||||
{
|
|
||||||
// Bad utf-8 string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clientId = null;
|
|
||||||
clientSecret = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Extracts forms authentication credentials from the HTTP request body.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="clientId"></param>
|
|
||||||
/// <param name="clientSecret"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "Optimized for usage")]
|
|
||||||
public bool TryGetFormCredentials(out string clientId, out string clientSecret)
|
|
||||||
{
|
|
||||||
clientId = Parameters[Constants.Parameters.ClientId];
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(clientId))
|
|
||||||
{
|
|
||||||
clientSecret = Parameters[Constants.Parameters.ClientSecret];
|
|
||||||
ClientId = clientId;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
clientId = null;
|
|
||||||
clientSecret = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains data about the OAuth client redirect URI
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthValidateClientRedirectUriContext : BaseValidatingClientContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthValidateClientRedirectUriContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="clientId"></param>
|
|
||||||
/// <param name="redirectUri"></param>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "3#", Justification = "redirect_uri is a string parameter")]
|
|
||||||
public OAuthValidateClientRedirectUriContext(HttpContext context, OAuthAuthorizationServerOptions options, string clientId, string redirectUri) : base(context, options, clientId)
|
|
||||||
{
|
|
||||||
RedirectUri = redirectUri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the client redirect URI
|
|
||||||
/// </summary>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "redirect_uri is a string parameter")]
|
|
||||||
public string RedirectUri { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marks this context as validated by the application. IsValidated becomes true and HasError becomes false as a result of calling.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public override bool Validated()
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(RedirectUri))
|
|
||||||
{
|
|
||||||
// Don't allow default validation when redirect_uri not provided with request
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return base.Validated();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks the redirect URI to determine whether it equals <see cref="RedirectUri"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="redirectUri"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings", MessageId = "0#", Justification = "redirect_uri is a string parameter")]
|
|
||||||
public bool Validated(string redirectUri)
|
|
||||||
{
|
|
||||||
if (redirectUri == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("redirectUri");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(RedirectUri) &&
|
|
||||||
!string.Equals(RedirectUri, redirectUri, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
// Don't allow validation to alter redirect_uri provided with request
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RedirectUri = redirectUri;
|
|
||||||
|
|
||||||
return Validated();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides context information used in validating an OAuth token request.
|
|
||||||
/// </summary>
|
|
||||||
public class OAuthValidateTokenRequestContext : BaseValidatingContext<OAuthAuthorizationServerOptions>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="OAuthValidateTokenRequestContext"/> class
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context"></param>
|
|
||||||
/// <param name="options"></param>
|
|
||||||
/// <param name="tokenRequest"></param>
|
|
||||||
/// <param name="clientContext"></param>
|
|
||||||
public OAuthValidateTokenRequestContext(HttpContext context, OAuthAuthorizationServerOptions options, TokenEndpointRequest tokenRequest, BaseValidatingClientContext clientContext) : base(context, options)
|
|
||||||
{
|
|
||||||
TokenRequest = tokenRequest;
|
|
||||||
ClientContext = clientContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the token request data.
|
|
||||||
/// </summary>
|
|
||||||
public TokenEndpointRequest TokenRequest { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets information about the client.
|
|
||||||
/// </summary>
|
|
||||||
public BaseValidatingClientContext ClientContext { get; private set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,164 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object representing the information contained in form encoded body of a Token endpoint request.
|
|
||||||
/// </summary>
|
|
||||||
public class TokenEndpointRequest
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance populated with values from the form encoded body parameters.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="parameters">Form encoded body parameters from a request.</param>
|
|
||||||
public TokenEndpointRequest(IReadableStringCollection parameters)
|
|
||||||
{
|
|
||||||
if (parameters == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("parameters");
|
|
||||||
}
|
|
||||||
|
|
||||||
Parameters = parameters;
|
|
||||||
GrantType = parameters[Constants.Parameters.GrantType];
|
|
||||||
ClientId = parameters[Constants.Parameters.ClientId];
|
|
||||||
if (string.Equals(GrantType, Constants.GrantTypes.AuthorizationCode, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
AuthorizationCodeGrant = new TokenEndpointRequestAuthorizationCode
|
|
||||||
{
|
|
||||||
Code = parameters[Constants.Parameters.Code],
|
|
||||||
RedirectUri = parameters[Constants.Parameters.RedirectUri],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (string.Equals(GrantType, Constants.GrantTypes.ClientCredentials, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
ClientCredentialsGrant = new TokenEndpointRequestClientCredentials
|
|
||||||
{
|
|
||||||
Scope = ((string)parameters[Constants.Parameters.Scope] ?? string.Empty).Split(' ')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (string.Equals(GrantType, Constants.GrantTypes.RefreshToken, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
RefreshTokenGrant = new TokenEndpointRequestRefreshToken
|
|
||||||
{
|
|
||||||
RefreshToken = parameters[Constants.Parameters.RefreshToken],
|
|
||||||
Scope = ((string)parameters[Constants.Parameters.Scope] ?? string.Empty).Split(' ')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (string.Equals(GrantType, Constants.GrantTypes.Password, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
ResourceOwnerPasswordCredentialsGrant = new TokenEndpointRequestResourceOwnerPasswordCredentials
|
|
||||||
{
|
|
||||||
UserName = parameters[Constants.Parameters.Username],
|
|
||||||
Password = parameters[Constants.Parameters.Password],
|
|
||||||
Scope = ((string)parameters[Constants.Parameters.Scope] ?? string.Empty).Split(' ')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrEmpty(GrantType))
|
|
||||||
{
|
|
||||||
CustomExtensionGrant = new TokenEndpointRequestCustomExtension
|
|
||||||
{
|
|
||||||
Parameters = parameters,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentException("No grant type found in the request");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The form encoded body parameters of the Token endpoint request
|
|
||||||
/// </summary>
|
|
||||||
public IReadableStringCollection Parameters { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "grant_type" parameter of the Token endpoint request. This parameter is required.
|
|
||||||
/// </summary>
|
|
||||||
public string GrantType { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The "client_id" parameter of the Token endpoint request. This parameter is optional. It might not
|
|
||||||
/// be present if the request is authenticated in a different way, for example, by using basic authentication
|
|
||||||
/// credentials.
|
|
||||||
/// </summary>
|
|
||||||
public string ClientId { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object available when the "grant_type" is "authorization_code".
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.1.3
|
|
||||||
/// </summary>
|
|
||||||
public TokenEndpointRequestAuthorizationCode AuthorizationCodeGrant { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object available when the "grant_type" is "client_credentials".
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.4.2
|
|
||||||
/// </summary>
|
|
||||||
public TokenEndpointRequestClientCredentials ClientCredentialsGrant { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object available when the "grant_type" is "refresh_token".
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-6
|
|
||||||
/// </summary>
|
|
||||||
public TokenEndpointRequestRefreshToken RefreshTokenGrant { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object available when the "grant_type" is "password".
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.3.2
|
|
||||||
/// </summary>
|
|
||||||
public TokenEndpointRequestResourceOwnerPasswordCredentials ResourceOwnerPasswordCredentialsGrant { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object available when the "grant_type" is unrecognized.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.5
|
|
||||||
/// </summary>
|
|
||||||
public TokenEndpointRequestCustomExtension CustomExtensionGrant { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True when the "grant_type" is "authorization_code".
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.1.3
|
|
||||||
/// </summary>
|
|
||||||
public bool IsAuthorizationCodeGrantType
|
|
||||||
{
|
|
||||||
get { return AuthorizationCodeGrant != null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True when the "grant_type" is "client_credentials".
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.4.2
|
|
||||||
/// </summary>
|
|
||||||
public bool IsClientCredentialsGrantType
|
|
||||||
{
|
|
||||||
get { return ClientCredentialsGrant != null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True when the "grant_type" is "refresh_token".
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-6
|
|
||||||
/// </summary>
|
|
||||||
public bool IsRefreshTokenGrantType
|
|
||||||
{
|
|
||||||
get { return RefreshTokenGrant != null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True when the "grant_type" is "password".
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.3.2
|
|
||||||
/// </summary>
|
|
||||||
public bool IsResourceOwnerPasswordCredentialsGrantType
|
|
||||||
{
|
|
||||||
get { return ResourceOwnerPasswordCredentialsGrant != null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// True when the "grant_type" is unrecognized.
|
|
||||||
/// See also http://tools.ietf.org/html/rfc6749#section-4.5
|
|
||||||
/// </summary>
|
|
||||||
public bool IsCustomExtensionGrantType
|
|
||||||
{
|
|
||||||
get { return CustomExtensionGrant != null; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object used by TokenEndpointRequest when the "grant_type" is "authorization_code".
|
|
||||||
/// </summary>
|
|
||||||
public class TokenEndpointRequestAuthorizationCode
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The value passed to the Token endpoint in the "code" parameter
|
|
||||||
/// </summary>
|
|
||||||
public string Code { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The value passed to the Token endpoint in the "redirect_uri" parameter. This MUST be provided by the caller
|
|
||||||
/// if the original visit to the Authorize endpoint contained a "redirect_uri" parameter.
|
|
||||||
/// </summary>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "By design")]
|
|
||||||
public string RedirectUri { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object used by TokenEndpointRequest when the "grant_type" is "client_credentials".
|
|
||||||
/// </summary>
|
|
||||||
public class TokenEndpointRequestClientCredentials
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The value passed to the Token endpoint in the "scope" parameter
|
|
||||||
/// </summary>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This class is just for passing data through.")]
|
|
||||||
public IList<string> Scope { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data object used by TokenEndpointRequest which contains parameter information when the "grant_type" is unrecognized.
|
|
||||||
/// </summary>
|
|
||||||
public class TokenEndpointRequestCustomExtension
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The parameter information when the "grant_type" is unrecognized.
|
|
||||||
/// </summary>
|
|
||||||
public IReadableStringCollection Parameters { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Data object used by TokenEndpointRequest when the "grant_type" parameter is "refresh_token".
|
|
||||||
/// </summary>
|
|
||||||
public class TokenEndpointRequestRefreshToken
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The value passed to the Token endpoint in the "refresh_token" parameter
|
|
||||||
/// </summary>
|
|
||||||
public string RefreshToken { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The value passed to the Token endpoint in the "scope" parameter
|
|
||||||
/// </summary>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This is just a data container object.")]
|
|
||||||
public IList<string> Scope { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.AuthServer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Data object used by TokenEndpointRequest when the "grant_type" is "password".
|
|
||||||
/// </summary>
|
|
||||||
public class TokenEndpointRequestResourceOwnerPasswordCredentials
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The value passed to the Token endpoint in the "username" parameter
|
|
||||||
/// </summary>
|
|
||||||
public string UserName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The value passed to the Token endpoint in the "password" parameter
|
|
||||||
/// </summary>
|
|
||||||
public string Password { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The value passed to the Token endpoint in the "scope" parameter
|
|
||||||
/// </summary>
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "This is just a data class.")]
|
|
||||||
public IList<string> Scope { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
{
|
|
||||||
"version": "1.0.5-*",
|
|
||||||
"description": "OAuth AspNet Server",
|
|
||||||
"authors": [
|
|
||||||
"Paul Schneider <paul@pschneider.fr>"
|
|
||||||
],
|
|
||||||
"packOptions": {
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/pazof/yavsc"
|
|
||||||
},
|
|
||||||
"licenseUrl": "https://github.com/pazof/yavsc/blob/vnext/LICENSE",
|
|
||||||
"requireLicenseAcceptance": true,
|
|
||||||
"owners": [
|
|
||||||
"Paul Schneider <paul@pschneider.fr>"
|
|
||||||
],
|
|
||||||
"summary": "Yet another very small company",
|
|
||||||
"projectUrl": "http://yavsc.pschneider.fr",
|
|
||||||
"tags": [
|
|
||||||
"Authorization server",
|
|
||||||
"OAuth",
|
|
||||||
"Web API"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tooling": {
|
|
||||||
"defaultNamespace": "Yavsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"Newtonsoft.Json": "7.0.1",
|
|
||||||
"Microsoft.AspNet.Identity.EntityFramework": "3.0.0-rc1-*",
|
|
||||||
"OAuth.AspNet.Token": {
|
|
||||||
"type": "build",
|
|
||||||
"target": "project"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"frameworks": {
|
|
||||||
"dnx451": {
|
|
||||||
"frameworkAssemblies": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
SOURCE_DIR=../..
|
|
||||||
MAKEFILE_DIR=$(SOURCE_DIR)/scripts/make
|
|
||||||
|
|
||||||
include $(MAKEFILE_DIR)/dnx.mk
|
|
||||||
include $(MAKEFILE_DIR)/versioning.mk
|
|
||||||
|
|
||||||
all: $(BINTARGETPATH)
|
|
||||||
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using Microsoft.AspNet.DataProtection;
|
|
||||||
|
|
||||||
public class MonoDataProtectionProvider : IDataProtectionProvider
|
|
||||||
{
|
|
||||||
private readonly string appName;
|
|
||||||
|
|
||||||
public MonoDataProtectionProvider()
|
|
||||||
: this(Guid.NewGuid().ToString())
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public MonoDataProtectionProvider(DirectoryInfo dataProtectionDirInfo)
|
|
||||||
: this(Guid.NewGuid().ToString())
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
public MonoDataProtectionProvider(string appName)
|
|
||||||
{
|
|
||||||
if (appName == null) { throw new ArgumentNullException("appName"); }
|
|
||||||
this.appName = appName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDataProtector Create(params string[] purposes)
|
|
||||||
{
|
|
||||||
if (purposes == null) { throw new ArgumentNullException("profile"); }
|
|
||||||
|
|
||||||
return new MonoDataProtector(appName, purposes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDataProtector CreateProtector(string purpose)
|
|
||||||
{
|
|
||||||
return Create(new string[] { purpose });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
//
|
|
||||||
// MonoDataProtector.cs
|
|
||||||
//
|
|
||||||
// Author:
|
|
||||||
// Paul Schneider <paul@pschneider.fr>
|
|
||||||
//
|
|
||||||
// Copyright (c) 2016 GNU GPL
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.IO;
|
|
||||||
using Microsoft.AspNet.DataProtection;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
public class MonoDataProtector : IDataProtector
|
|
||||||
{
|
|
||||||
private const string PRIMARY_PURPOSE = "IDataProtector";
|
|
||||||
|
|
||||||
private readonly string appName;
|
|
||||||
private readonly DataProtectionScope dataProtectionScope;
|
|
||||||
private readonly string[] purposes;
|
|
||||||
|
|
||||||
public MonoDataProtector(string appName, string[] purposes)
|
|
||||||
{
|
|
||||||
if (appName == null) { throw new ArgumentNullException("appName"); }
|
|
||||||
if (purposes == null) { throw new ArgumentNullException("purposes"); }
|
|
||||||
|
|
||||||
this.appName = appName;
|
|
||||||
this.purposes = purposes;
|
|
||||||
this.dataProtectionScope = DataProtectionScope.CurrentUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDataProtector CreateProtector(string purpose)
|
|
||||||
{
|
|
||||||
if (purposes.Contains(purpose))
|
|
||||||
return new MonoDataProtector(appName, new string[] { purpose });
|
|
||||||
return new MonoDataProtector(appName, new string[] { });
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Protect(byte[] userData)
|
|
||||||
{
|
|
||||||
return ProtectedData.Protect(userData, this.GetEntropy(), dataProtectionScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Unprotect(byte[] protectedData)
|
|
||||||
{
|
|
||||||
return ProtectedData.Unprotect(protectedData, this.GetEntropy(), dataProtectionScope);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] GetEntropy()
|
|
||||||
{
|
|
||||||
using (SHA256 sha256 = SHA256.Create())
|
|
||||||
{
|
|
||||||
using (MemoryStream memoryStream = new MemoryStream())
|
|
||||||
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, sha256, CryptoStreamMode.Write))
|
|
||||||
using (StreamWriter writer = new StreamWriter(cryptoStream))
|
|
||||||
{
|
|
||||||
writer.Write(this.appName);
|
|
||||||
writer.Write(PRIMARY_PURPOSE);
|
|
||||||
|
|
||||||
foreach (string purpose in this.purposes)
|
|
||||||
{
|
|
||||||
writer.Write(purpose);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sha256.Hash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
using Microsoft.AspNet.Authentication;
|
|
||||||
using Microsoft.AspNet.DataProtection;
|
|
||||||
using System;
|
|
||||||
using System.IdentityModel.Tokens;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace OAuth.AspNet.Tokens
|
|
||||||
{
|
|
||||||
public class TicketDataFormatTokenValidator : ISecurityTokenValidator
|
|
||||||
{
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
public TicketDataFormatTokenValidator(IDataProtectionProvider dataProtectionProvider, string purpose = "AccessToken") : this(dataProtectionProvider, purpose , new string [] { "v1" }) { }
|
|
||||||
|
|
||||||
public TicketDataFormatTokenValidator(IDataProtectionProvider dataProtectionProvider, string purpose, string [] subPurposes)
|
|
||||||
{
|
|
||||||
if (dataProtectionProvider == null)
|
|
||||||
{
|
|
||||||
dataProtectionProvider = new MonoDataProtectionProvider(System.AppDomain.CurrentDomain.FriendlyName)
|
|
||||||
.CreateProtector("profile");
|
|
||||||
}
|
|
||||||
_ticketDataFormat = new TicketDataFormat(dataProtectionProvider.CreateProtector(purpose, subPurposes));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region non-Public Members
|
|
||||||
|
|
||||||
private readonly TicketDataFormat _ticketDataFormat;
|
|
||||||
|
|
||||||
private const string _serializationRegex = @"^[A-Za-z0-9-_]*$";
|
|
||||||
|
|
||||||
private int _maximumTokenSizeInBytes = TokenValidationParameters.DefaultMaximumTokenSizeInBytes;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Public Members
|
|
||||||
|
|
||||||
public bool CanValidateToken
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int MaximumTokenSizeInBytes
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _maximumTokenSizeInBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value < 1)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(MaximumTokenSizeInBytes), "Negative or zero-sized tokens are invalid.");
|
|
||||||
|
|
||||||
_maximumTokenSizeInBytes = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanReadToken(string securityToken)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(securityToken))
|
|
||||||
throw new ArgumentException("Security token has no value.", nameof(securityToken));
|
|
||||||
|
|
||||||
if (securityToken.Length * 2 > this.MaximumTokenSizeInBytes)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (Regex.IsMatch(securityToken, _serializationRegex))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
|
|
||||||
{
|
|
||||||
AuthenticationTicket ticket = _ticketDataFormat.Unprotect(securityToken);
|
|
||||||
|
|
||||||
validatedToken = null;
|
|
||||||
|
|
||||||
return ticket?.Principal;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
{
|
|
||||||
"version": "1.0.5-*",
|
|
||||||
"description": "OAuth AspNet Token",
|
|
||||||
"authors": [
|
|
||||||
"Paul Schneider <paul@pschneider.fr>"
|
|
||||||
],
|
|
||||||
"packOptions": {
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/pazof/yavsc"
|
|
||||||
},
|
|
||||||
"licenseUrl": "https://github.com/pazof/yavsc/blob/vnext/LICENSE",
|
|
||||||
"requireLicenseAcceptance": true,
|
|
||||||
"owners": [
|
|
||||||
"Paul Schneider <paul@pschneider.fr>"
|
|
||||||
],
|
|
||||||
"summary": "Yet another very small company",
|
|
||||||
"projectUrl": "http://yavsc.pschneider.fr",
|
|
||||||
"tags": [
|
|
||||||
"Authorization server",
|
|
||||||
"OAuth",
|
|
||||||
"Web API"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tooling": {
|
|
||||||
"defaultNamespace": "Yavsc"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"Newtonsoft.Json": "7.0.1",
|
|
||||||
"Microsoft.AspNet.Authentication.JwtBearer": "1.0.0-rc1-final",
|
|
||||||
"Microsoft.AspNet.DataProtection": "1.0.0-rc1-final"
|
|
||||||
},
|
|
||||||
"frameworks": {
|
|
||||||
"dnx451": {
|
|
||||||
"frameworkAssemblies": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"postrestore": [
|
|
||||||
"grep -v '\\.\\.dll' project.lock.json > new.project.lock.json",
|
|
||||||
"mv new.project.lock.json project.lock.json"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
namespace Yavsc.Server
|
namespace Yavsc.Server
|
||||||
{
|
{
|
||||||
using Microsoft.AspNet.Http;
|
|
||||||
using Yavsc.Models.Auth;
|
|
||||||
|
|
||||||
public static class ServerConstants
|
public static class ServerConstants
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.AspNet.Identity.EntityFramework;
|
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Yavsc.Models.Relationship;
|
||||||
|
using Yavsc.Models.Relationship;
|
||||||
|
using Yavsc.Models.Identity;
|
||||||
|
using Yavsc.Models.Chat;
|
||||||
|
using Yavsc.Models.Bank;
|
||||||
|
using Yavsc.Models.Access;
|
||||||
namespace Yavsc.Models
|
namespace Yavsc.Models
|
||||||
{
|
{
|
||||||
using Models.Relationship;
|
|
||||||
using Models.Identity;
|
|
||||||
using Models.Chat;
|
|
||||||
using Models.Bank;
|
|
||||||
using Models.Access;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
public class ApplicationUser : IdentityUser, IBaseTrackedEntity
|
public class ApplicationUser : IdentityUser, IBaseTrackedEntity
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Another me, as a byte array.
|
/// Another me, as a byte array.
|
||||||
/// This value points a picture that may be used
|
/// This value points a picture that may be used
|
||||||
|
|
@ -36,31 +37,31 @@ namespace Yavsc.Models
|
||||||
/// WIP Paypal
|
/// WIP Paypal
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[Display(Name="Account balance")]
|
[Display(Name = "Account balance")]
|
||||||
public virtual AccountBalance AccountBalance { get; set; }
|
public virtual AccountBalance AccountBalance { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// User's posts
|
/// User's posts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[InverseProperty("Author"),JsonIgnore]
|
[InverseProperty("Author"), JsonIgnore]
|
||||||
public virtual List<Blog.BlogPost> Posts { get; set; }
|
public virtual List<Blog.BlogPost> Posts { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// User's contact list
|
/// User's contact list
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[InverseProperty("Owner"),JsonIgnore]
|
[InverseProperty("Owner"), JsonIgnore]
|
||||||
public virtual List<Contact> Book { get; set; }
|
public virtual List<Contact> Book { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// External devices using the API
|
/// External devices using the API
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[InverseProperty("DeviceOwner"),JsonIgnore]
|
[InverseProperty("DeviceOwner"), JsonIgnore]
|
||||||
public virtual List<DeviceDeclaration> DeviceDeclaration { get; set; }
|
public virtual List<DeviceDeclaration> DeviceDeclaration { get; set; }
|
||||||
|
|
||||||
[InverseProperty("Owner"),JsonIgnore]
|
[InverseProperty("Owner"), JsonIgnore]
|
||||||
public virtual List<ChatConnection> Connections { get; set; }
|
public virtual List<ChatConnection> Connections { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -68,9 +69,9 @@ namespace Yavsc.Models
|
||||||
/// User's circles
|
/// User's circles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[InverseProperty("Owner"),JsonIgnore]
|
[InverseProperty("Owner"), JsonIgnore]
|
||||||
|
|
||||||
public virtual List<Circle> Circles { get; set; }
|
public virtual List<Circle> Circles { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Billing postal address
|
/// Billing postal address
|
||||||
|
|
@ -87,29 +88,34 @@ namespace Yavsc.Models
|
||||||
[MaxLength(512)]
|
[MaxLength(512)]
|
||||||
public string DedicatedGoogleCalendar { get; set; }
|
public string DedicatedGoogleCalendar { get; set; }
|
||||||
|
|
||||||
public override string ToString() {
|
public override string ToString()
|
||||||
return this.Id+" "+this.AccountBalance?.Credits.ToString()+this.Email+" "+this.UserName+" $"+this.AccountBalance?.Credits.ToString();
|
{
|
||||||
|
return this.Id + " " + this.AccountBalance?.Credits.ToString() + this.Email + " " + this.UserName + " $" + this.AccountBalance?.Credits.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BankIdentity BankInfo { get; set; }
|
public BankIdentity BankInfo { get; set; }
|
||||||
|
|
||||||
public long DiskQuota { get; set; } = 512*1024*1024;
|
public long DiskQuota { get; set; } = 512 * 1024 * 1024;
|
||||||
public long DiskUsage { get; set; } = 0;
|
public long DiskUsage { get; set; } = 0;
|
||||||
|
|
||||||
public long MaxFileSize { get; set; } = 512*1024*1024;
|
public long MaxFileSize { get; set; } = 512 * 1024 * 1024;
|
||||||
|
|
||||||
[JsonIgnore][InverseProperty("Owner")]
|
[JsonIgnore]
|
||||||
|
[InverseProperty("Owner")]
|
||||||
public virtual List<BlackListed> BlackList { get; set; }
|
public virtual List<BlackListed> BlackList { get; set; }
|
||||||
|
|
||||||
public bool AllowMonthlyEmail { get; set; } = false;
|
public bool AllowMonthlyEmail { get; set; } = false;
|
||||||
|
|
||||||
[JsonIgnore][InverseProperty("Owner")]
|
[JsonIgnore]
|
||||||
|
[InverseProperty("Owner")]
|
||||||
public virtual List<ChatRoom> Rooms { get; set; }
|
public virtual List<ChatRoom> Rooms { get; set; }
|
||||||
|
|
||||||
[JsonIgnore][InverseProperty("User")]
|
[JsonIgnore]
|
||||||
|
[InverseProperty("User")]
|
||||||
public virtual List<ChatRoomAccess> RoomAccess { get; set; }
|
public virtual List<ChatRoomAccess> RoomAccess { get; set; }
|
||||||
|
|
||||||
[JsonIgnore][InverseProperty("Member")]
|
[JsonIgnore]
|
||||||
|
[InverseProperty("Member")]
|
||||||
public virtual List<CircleMember> Membership { get; set; }
|
public virtual List<CircleMember> Membership { get; set; }
|
||||||
|
|
||||||
public DateTime DateCreated
|
public DateTime DateCreated
|
||||||
|
|
@ -120,13 +126,13 @@ namespace Yavsc.Models
|
||||||
public string UserCreated
|
public string UserCreated
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime DateModified
|
public DateTime DateModified
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string UserModified
|
public string UserModified
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
|
|
|
||||||
28
src/Yavsc.Server/Yavsc.Server.csproj
Normal file
28
src/Yavsc.Server/Yavsc.Server.csproj
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.4">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.5" />
|
||||||
|
<PackageReference Include="Google.Apis.Calendar.v3" Version="1.60.0.2993" />
|
||||||
|
<PackageReference Include="PayPalMerchantSDK" Version="2.16.250" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="System.Net" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../Yavsc.Abstract/Yavsc.Abstract.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
34
yavsc.sln
Normal file
34
yavsc.sln
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yavsc.Abstract", "src\Yavsc.Abstract\Yavsc.Abstract.csproj", "{5AFB6255-CF1B-4660-BB35-F24C8C75FECE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yavsc.Server", "src\Yavsc.Server\Yavsc.Server.csproj", "{830F5A71-0192-4288-9F4D-D7849D958970}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{5AFB6255-CF1B-4660-BB35-F24C8C75FECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5AFB6255-CF1B-4660-BB35-F24C8C75FECE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5AFB6255-CF1B-4660-BB35-F24C8C75FECE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5AFB6255-CF1B-4660-BB35-F24C8C75FECE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{830F5A71-0192-4288-9F4D-D7849D958970}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{830F5A71-0192-4288-9F4D-D7849D958970}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{830F5A71-0192-4288-9F4D-D7849D958970}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{830F5A71-0192-4288-9F4D-D7849D958970}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{5AFB6255-CF1B-4660-BB35-F24C8C75FECE} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
||||||
|
{830F5A71-0192-4288-9F4D-D7849D958970} = {503DDD6B-BE10-4235-9EBD-E9B1FA6067DF}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Loading…
Add table
Add a link
Reference in a new issue