Skip to content

Instantly share code, notes, and snippets.

@IcodeNet
Created October 10, 2012 07:06
Show Gist options
  • Save IcodeNet/3863635 to your computer and use it in GitHub Desktop.
Save IcodeNet/3863635 to your computer and use it in GitHub Desktop.
Oauth and SS
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