This repository has been archived by the owner on Dec 14, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathOAuth2Client.cs
179 lines (156 loc) · 6.18 KB
/
OAuth2Client.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Routing;
using System.Web.Security;
using System.Web.Mvc;
namespace BrockAllen.OAuth2
{
public class OAuth2Client
{
public static Uri OAuthCallbackOrigin { get; set; }
public static string OAuthCallbackUrl { get; set; }
public static bool AutoRegisterOAuthCallbackUrl { get; set; }
public static string AuthorizationContextCookieName { get; set; }
static OAuth2Client instance = new OAuth2Client();
public static OAuth2Client Instance
{
get { return instance; }
}
static OAuth2Client()
{
AutoRegisterOAuthCallbackUrl = false;
OAuthCallbackUrl = "oauth2callback";
AuthorizationContextCookieName = "oauth2authctx";
}
private OAuth2Client()
{
}
public OAuth2Client(ProviderType providerType, string clientID, string clientSecret, string scope = null)
{
this.RegisterProvider(providerType, clientID, clientSecret, scope);
}
public static void RegisterCustomOAuthCallback(RouteCollection routes, string action, string controller, string area = null)
{
routes.MapRoute(
"OAuthCallback",
OAuth2Client.OAuthCallbackUrl,
new { controller, action, area });
}
ConcurrentDictionary<ProviderType, Provider> providers = new ConcurrentDictionary<ProviderType, Provider>();
public void RegisterProvider(ProviderType providerType, string clientID, string clientSecret, string scope = null, NameValueCollection additionalParameters = null)
{
Provider provider = null;
switch (providerType)
{
case ProviderType.Google:
provider = new GoogleProvider(clientID, clientSecret, scope, additionalParameters);
break;
case ProviderType.Live:
provider = new LiveProvider(clientID, clientSecret, scope, additionalParameters);
break;
case ProviderType.Facebook:
provider = new FacebookProvider(clientID, clientSecret, scope, additionalParameters);
break;
case ProviderType.LinkedIn:
provider = new LinkedInProvider(clientID, clientSecret, scope, additionalParameters);
break;
}
if (provider == null)
{
throw new ArgumentException("Invalid provider type");
}
providers[providerType] = provider;
}
internal Provider GetProvider(ProviderType providerType)
{
var provider = providers[providerType];
if (provider == null)
{
throw new ArgumentException("Invalid provider type");
}
return provider;
}
public void RedirectToAuthorizationProvider(
ProviderType providerType, string returnUrl = null)
{
var provider = this.GetProvider(providerType);
var redirect = provider.GetRedirect();
var authCtx = new AuthorizationContext
{
ProviderType = providerType,
ReturnUrl = returnUrl,
State = redirect.State
};
SaveContext(authCtx);
var ctx = HttpContext.Current;
ctx.Response.Redirect(redirect.AuthorizationUrl);
}
public async Task<CallbackResult> ProcessCallbackAsync()
{
var authCtx = GetContext();
if (authCtx == null)
{
return new CallbackResult
{
Error = "No Authorization Context Cookie"
};
}
var provider = GetProvider(authCtx.ProviderType);
var ctx = HttpContext.Current;
var result = await provider.ProcessCallbackAsync(authCtx, ctx.Request.QueryString);
result.ReturnUrl = authCtx.ReturnUrl;
result.ProviderName = authCtx.ProviderType.ToString();
return result;
}
void SaveContext(AuthorizationContext authCtx)
{
var ctx = HttpContext.Current;
var json = authCtx.ToJson();
var data = Protect(Encoding.UTF8.GetBytes(json));
var cookie = new HttpCookie(AuthorizationContextCookieName, data);
cookie.Secure = ctx.Request.IsSecureConnection;
cookie.HttpOnly = true;
cookie.Path = ctx.Request.ApplicationPath;
ctx.Response.Cookies.Add(cookie);
}
AuthorizationContext GetContext()
{
var ctx = HttpContext.Current;
var cookie = ctx.Request.Cookies[AuthorizationContextCookieName];
if (cookie == null) return null;
var json = Encoding.UTF8.GetString(Unprotect(cookie.Value));
var authCtx = AuthorizationContext.Parse(json);
cookie = new HttpCookie(AuthorizationContextCookieName, ".");
cookie.Secure = ctx.Request.IsSecureConnection;
cookie.HttpOnly = true;
cookie.Path = ctx.Request.ApplicationPath;
cookie.Expires = DateTime.UtcNow.AddYears(-1);
ctx.Response.Cookies.Add(cookie);
return authCtx;
}
const string MachineKeyPurpose = "BrockAllen.OAuth2";
string Protect(byte[] data)
{
if (data == null || data.Length == 0) return null;
var value = MachineKey.Protect(data, MachineKeyPurpose);
return Convert.ToBase64String(value);
}
byte[] Unprotect(string value)
{
if (String.IsNullOrWhiteSpace(value)) return null;
var bytes = Convert.FromBase64String(value);
return MachineKey.Unprotect(bytes, MachineKeyPurpose);
}
}
}