Created
October 10, 2012 07:06
-
-
Save IcodeNet/3863635 to your computer and use it in GitHub Desktop.
Oauth and SS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Mvc 3.0 project that hosts my Services using Service stack | |
Same MVc 3.0 project that holds my controllers responsible for generating the Request Token and Access Token for Oauth authentication | |
In the same MVC project I have an AccountController that my secure services are directed to its “login” action through [Authenticate(HtmlRedirect = "/account/login")] | |
Currently the RequestTokenController returns a hard coded “code” for all requests and the AccessTokenController a hardcoded “access_code” | |
They achieve this through simple redirection to the redirect_uri which is <baseURL>/auth/<provider> | |
As in the following | |
Response.Redirect(redirect_uri + "?code=4512391789087"); | |
And | |
Response.Redirect(redirect_uri + "?access_token=AAAFgXIZCtQZCoBALLQ7gLOgtJJHA0vBZCPggo0vSe8EZCkMJSh38fN4UQ4oi8bF7UMVWP1KjqZCTELjsRW6BvHSsfvvxLo6j4Hwc5GtqjKwZDZD"); | |
My Authenticate method in my <provider> is | |
public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request) | |
{ | |
var tokens = Init(authService, ref session, request); | |
var code = authService.RequestContext.Get<IHttpRequest>().QueryString["code"]; | |
var isPreAuthCallback = !code.IsNullOrEmpty(); | |
if (!isPreAuthCallback) | |
{ | |
var preAuthUrl = PreAuthUrl + "?client_id={0}&redirect_uri={1}&scope={2}" | |
.Fmt(AppId, this.CallbackUrl.UrlEncode(), string.Join(",", Permissions)); | |
authService.SaveSession(session, SessionExpiry); | |
return authService.Redirect(preAuthUrl); | |
} | |
var accessTokenUrl = this.AccessTokenUrl + "?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}" | |
.Fmt(AppId, this.CallbackUrl.UrlEncode(), AppSecret, code); | |
try | |
{ | |
var contents = accessTokenUrl.DownloadUrl(); | |
var authInfo = HttpUtility.ParseQueryString(contents); | |
tokens.AccessTokenSecret = authInfo["access_token"]; | |
session.IsAuthenticated = true; | |
authService.SaveSession(session, SessionExpiry); | |
OnAuthenticated(authService, session, tokens, authInfo.ToDictionary()); | |
//Haz access! | |
return authService.Redirect(session.ReferrerUrl.AddHashParam("s", "1")); | |
} | |
catch (WebException we) | |
{ | |
var statusCode = ((HttpWebResponse)we.Response).StatusCode; | |
if (statusCode == HttpStatusCode.BadRequest) | |
{ | |
return authService.Redirect(session.ReferrerUrl.AddHashParam("f", "AccessTokenFailed")); | |
} | |
} | |
//Shouldn't get here | |
return authService.Redirect(session.ReferrerUrl.AddHashParam("f", "Unknown")); | |
} | |
And this is where everything falls into pieces. The request enters a loop and it time outs... | |
Any ideas of how to implement this? | |
My request services etc snippets follow... | |
// Request | |
[DataContract] | |
[Route("/members/{Id}")] | |
[Authenticate(HtmlRedirect = "/account/login")] | |
public class MemberDetailsRequest | |
{ | |
[DataMember] | |
public string Id { get; set; } | |
[DataMember] | |
public int Version { get; set; } | |
} | |
//Service | |
[Authenticate(HtmlRedirect = "/account/login")] | |
public class MemberDetailsService : RestServiceBase<MemberDetailsRequest> | |
{ | |
........................... | |
// Login Controller | |
public class AccountController : SSControllerBase | |
{ | |
[System.Web.Mvc.HttpPost] | |
[AllowAnonymous] | |
/* [ValidateAntiForgeryToken]*/ | |
public void Login(LoginModel model, string returnUrl) | |
{ | |
if (ModelState.IsValid) | |
{ | |
try | |
{ | |
var authRequest = new Auth { /*provider = "rp", */ UserName = model.UserName, Continue = returnUrl, Password = model.Password }; | |
//Most services don't need the HTTP Request Context, | |
//but since the AuthService sets cookies on the HTTP response, it does. So you need to set it with: | |
//Services that make use of the RequestContext, needs to be the injected with the current Request Context, | |
AuthService.RequestContext = new HttpRequestContext( | |
System.Web.HttpContext.Current.Request.ToRequest(), | |
System.Web.HttpContext.Current.Response.ToResponse(), | |
authRequest); | |
AuthResponse result = AuthService.Authenticate(authRequest); | |
var alreadyAuthenticated = result == null; //Returning null means user was already authenticated (and no attempt was made). Returning non-null means the user authentication was successful. Any Authentication failure will throw an exception. | |
if (alreadyAuthenticated) | |
{ | |
Redirect(returnUrl); | |
} | |
/* return alreadyAuthenticated | |
? View("success") //An Auth attempt was successful | |
: View("alreadyAuthenticated"); //No Auth attempt was made because they were already authenticated*/ | |
} | |
catch (Exception ex) | |
{ | |
ModelState.AddModelError("", "The user name or password provided is incorrect."); | |
} | |
} | |
} | |
///Authenticate from provider | |
public override object Authenticate(IServiceBase authService, IAuthSession session, Auth request) | |
{ | |
var tokens = Init(authService, ref session, request); | |
var code = authService.RequestContext.Get<IHttpRequest>().QueryString["code"]; | |
var isPreAuthCallback = !code.IsNullOrEmpty(); | |
if (!isPreAuthCallback) | |
{ | |
var preAuthUrl = PreAuthUrl + "?client_id={0}&redirect_uri={1}&scope={2}" | |
.Fmt(AppId, this.CallbackUrl.UrlEncode(), string.Join(",", Permissions)); | |
authService.SaveSession(session, SessionExpiry); | |
return authService.Redirect(preAuthUrl); | |
} | |
var accessTokenUrl = this.AccessTokenUrl + "?client_id={0}&redirect_uri={1}&client_secret={2}&code={3}" | |
.Fmt(AppId, this.CallbackUrl.UrlEncode(), AppSecret, code); | |
try | |
{ | |
var contents = accessTokenUrl.DownloadUrl(); | |
var authInfo = HttpUtility.ParseQueryString(contents); | |
tokens.AccessTokenSecret = authInfo["access_token"]; | |
session.IsAuthenticated = true; | |
authService.SaveSession(session, SessionExpiry); | |
OnAuthenticated(authService, session, tokens, authInfo.ToDictionary()); | |
//Haz access! | |
return authService.Redirect(session.ReferrerUrl.AddHashParam("s", "1")); | |
} | |
catch (WebException we) | |
{ | |
var statusCode = ((HttpWebResponse)we.Response).StatusCode; | |
if (statusCode == HttpStatusCode.BadRequest) | |
{ | |
return authService.Redirect(session.ReferrerUrl.AddHashParam("f", "AccessTokenFailed")); | |
} | |
} | |
//Shouldn't get here | |
return authService.Redirect(session.ReferrerUrl.AddHashParam("f", "Unknown")); | |
} | |
// and | |
public class RequestTokenController : Controller | |
{ | |
// | |
// GET: /RequestToken/ | |
public void Index(string redirect_uri) | |
{ | |
Response.Redirect(redirect_uri + "?code=45"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment