HttpContext.GetOwinContext().Authentication.GetExternalLoginInfoAsync() always return null after successfully login using OKTA SAML2.0 - owin

I'm currently trying to get Okta to work with our ASP.Net MVC 4.7 based application. what i observe okta login get successfully but Unfortunatly After the authentication (saml response accepted) challenge, ExternalLoginCallback is called then checks if Okta info is present to use for own authentication but it always return null refer ExternalLoginCallback method. or https://github.com/bvillanueva-mdsol/OktaSaml2OwinSample/issues/1 as code base and also raised issue in git hub for respective owner.
<add key="ApplicationBaseUri" value="https://localhost:2687" />
<add key="IdentityProviderIssuer" value="http://www.okta.com/exk3js0t73vBlN4Vq5d7" />
<add key="IdentityProviderSsoUri" value="https://dev-00349616.okta.com/app/dev-00349616_httpslocalhost2687signinsaml_1/exk3js0t73vBlN4Vq5d7/sso/saml" />
public void Configuration(IAppBuilder app)
{
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
AuthenticationMode = AuthenticationMode.Active
});
app.UseSaml2Authentication(CreateSaml2Options());
}
private static Saml2AuthenticationOptions CreateSaml2Options()
{
var applicationBaseUri = new Uri(ConfigurationManager.AppSettings["ApplicationBaseUri"]);
var saml2BaseUri = new Uri(applicationBaseUri, "saml2");
var identityProviderIssuer = ConfigurationManager.AppSettings["IdentityProviderIssuer"];
var identityProviderSsoUri = new Uri(ConfigurationManager.AppSettings["IdentityProviderSsoUri"]);
var Saml2Options = new Saml2AuthenticationOptions(false)
{
SPOptions = new SPOptions
{
EntityId = new EntityId(saml2BaseUri.AbsoluteUri),
ReturnUrl = applicationBaseUri
}
};
var identityProvider = new IdentityProvider(new EntityId(identityProviderIssuer), Saml2Options.SPOptions)
{
AllowUnsolicitedAuthnResponse = true,
Binding = Saml2BindingType.HttpRedirect,
SingleSignOnServiceUrl = identityProviderSsoUri
};
identityProvider.SigningKeys.AddConfiguredKey(
new X509Certificate2(
HostingEnvironment.MapPath(
"~/App_Data/okta.cert")));
Saml2Options.IdentityProviders.Add(identityProvider);
return Saml2Options;
}
AccountController.cs file
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
//ControllerContext.HttpContext.Session.RemoveAll();
return new Saml2ChallengeResult(Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await HttpContext.GetOwinContext().Authentication.GetExternalLoginInfoAsync();
if (loginInfo == null) // always return null
{
return RedirectToAction("LoginError");
}
var identity = new ClaimsIdentity(loginInfo.ExternalIdentity.Claims,
DefaultAuthenticationTypes.ApplicationCookie);
var authProps = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTime.UtcNow.AddMinutes(1)
};
HttpContext.GetOwinContext().Authentication.SignIn(authProps, identity);
return RedirectToLocal(returnUrl);
}
[AllowAnonymous]
public ActionResult LoginError()
{
return Content("Error Logging in!");
}
private IAuthenticationManager AuthenticationManager =>
HttpContext.GetOwinContext().Authentication;
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}
internal class Saml2ChallengeResult : HttpUnauthorizedResult
{
public string RedirectUri { get; set; }
public Saml2ChallengeResult(string redirectUri)
{
RedirectUri = redirectUri;
}
public override void ExecuteResult(ControllerContext context)
{
context.RequestContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, "Saml2");
}
}
}

Solution is more related to correct steps which I missed.
code is absolutely fine and it will work
In order to run the application we have roslyn folder in bin folder and by mistake I copied roslyn folder from RUUNING https://localhost:44376 application. We should not copy and paste roslyn folder from running application to https://localhost:2687.
Clue :
surprisingly IIS shows 2 application running even https://localhost:44376 visual studio application was closed.
and now I am getting login info details from okta

Related

How to add additional parameter to my azure ad login link to modify the login functionality?

Right now I am working with the application which automatically logs in user through microsoft account after user enters the credentials once. This is how I am trying to call the microsoft login:
public partial class Startup
{
// Load configuration settings from PrivateSettings.config
private static string appId = ConfigurationManager.AppSettings["ida:AppId"];
private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
private static string tenantId = ConfigurationManager.AppSettings["ida:tenantId"];
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
public static string authority = aadInstance + tenantId;
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseKentorOwinCookieSaver();
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = appId,
Authority = authority,
RedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
}
}
);
}
private static Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage,
OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
string redirect = $"Home/Error?message={notification.Exception.Message}";
if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
{
redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}";
}
notification.Response.Redirect(redirect);
return Task.FromResult(0);
}
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
var idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithTenantId(tenantId)
.WithClientSecret(appSecret)
.Build();
string email = string.Empty;
try
{
string[] scopes = null;
var result = await idClient.AcquireTokenByAuthorizationCode(
scopes, notification.Code).ExecuteAsync();
email = await GraphHelper.GetUserDetailsAsync(result.AccessToken);
var account = await idClient.GetAccountAsync(result.Account.HomeAccountId.Identifier);
await idClient.RemoveAsync(account);//
}
catch (MsalException ex)
{
System.Diagnostics.Trace.TraceError(ex.Message);
}
notification.HandleResponse();
notification.Response.Redirect($"Account/SignInAzureEmailAsync?email={email}");
}
}
<add key="ida:AADInstance" value="https://login.microsoftonline.com/" />
I read this Microsoft document where is suggested me to use prompt=login which forces user to login every time they click on login button. I couldn't figure out how to apply this modification in my link. Any suggestions please?
You can use RedirectToIdentityProvider function to configure the prompt property
Notifications = new OpenIdConnectAuthenticationNotifications()
{
RedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("prompt", "login");
return Task.FromResult(0);
}
}
};

Authentication with multiple Azure AD Instances Episerver

We have been asked to provide Azure ADFS SSO capability for a customer. This is for a new Episerver CMS site version 11. The original request was to have just the one, which I was able to build no problem. The problems I'm having now is trying to authenticate using two Azure Tenants. I came across this article https://blogs.perficient.com/2021/01/22/episerver-authentication-with-multiple-azure-ad-instances/ and then also this one https://world.optimizely.com/forum/developer-forum/CMS/Thread-Container/2018/10/configuring-episerver-cms-to-use-2-different-adfs-environments/ - where there hasn't been any response... and dates back to 2018
This issue I'm getting following David Lewis example is I' can't seem to hit the code set in the 'AppStartupServices.cs'
This is my code:
private static readonly string tenant_1TenantId = ConfigurationManager.AppSettings["Tenant_1AzureAD:Tenant"];
// <add key="AzureAD:ClientID" value="Client ID from Azure AD application" />
private static readonly string tenant_1ClientId = ConfigurationManager.AppSettings["Tenant_1AzureAD:ClientID"];
private static readonly string tenant_1CommonAuthority = string.Format(CultureInfo.InvariantCulture, tenant_1TenantId, "common/");
// <add key="AzureAD:Tenant" value="https://login.microsoftonline.com/{0}" />
private static readonly string tenantId = ConfigurationManager.AppSettings["AzureAD:Tenant"];
// <add key="AzureAD:ClientID" value="Client ID from Azure AD application" />
private static readonly string clientId = ConfigurationManager.AppSettings["AzureAD:ClientID"];
//<add key="AzureAD:RedirectUri" value="https://the logout post uri/" />
private static readonly string azureRedirectUri = ConfigurationManager.AppSettings["AzureAD:RedirectUri"];
private static readonly string commonAuthority = string.Format(CultureInfo.InvariantCulture, tenantId, "common/");
const string logoutPath = "/Util/logout.aspx";
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions("tenant_1")
{
ClientId = tenant_1ClientId,
Authority = tenant_1CommonAuthority,
PostLogoutRedirectUri = azureRedirectUri,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
RoleClaimType = ClaimTypes.Role
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = context =>
{
if (context.Exception.Message.Contains("IDX21323"))
{
context.SkipToNextMiddleware();
return Task.FromResult(0);
}
else
{
context.HandleResponse();
context.Response.Write(context.Exception.Message);
return Task.FromResult(0);
}
},
RedirectToIdentityProvider = context =>
{
// Here you can change the return uri based on multi sites
HandleMultiSiteReturnUrl(context);
// To avoid a redirect loop to the federation server send 403
// when user is authenticated but does not have access
if (context.OwinContext.Response.StatusCode == 401 &&
context.OwinContext.Authentication.User.Identity.IsAuthenticated)
{
context.OwinContext.Response.StatusCode = 403;
context.HandleResponse();
}
return Task.FromResult(0);
},
SecurityTokenValidated = (ctx) =>
{
var redirectUri = new Uri(ctx.AuthenticationTicket.Properties.RedirectUri, UriKind.RelativeOrAbsolute);
if (redirectUri.IsAbsoluteUri)
{
ctx.AuthenticationTicket.Properties.RedirectUri = redirectUri.PathAndQuery;
}
//Sync user and the roles to EPiServer in the background
ServiceLocator.Current.GetInstance<ISynchronizingUserService>().
SynchronizeAsync(ctx.AuthenticationTicket.Identity);
return Task.FromResult(0);
}
}
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions("tenant_2")
{
ClientId = clientId,
Authority = commonAuthority,
PostLogoutRedirectUri = azureRedirectUri,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
RoleClaimType = ClaimTypes.Role
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Write(context.Exception.Message);
return Task.FromResult(0);
},
RedirectToIdentityProvider = context =>
{
// Here you can change the return uri based on multi sites
HandleMultiSiteReturnUrl(context);
// To avoid a redirect loop to the federation server send 403
// when user is authenticated but does not have access
if (context.OwinContext.Response.StatusCode == 401 &&
context.OwinContext.Authentication.User.Identity.IsAuthenticated)
{
context.OwinContext.Response.StatusCode = 403;
context.HandleResponse();
}
return Task.FromResult(0);
},
SecurityTokenValidated = (ctx) =>
{
var redirectUri = new Uri(ctx.AuthenticationTicket.Properties.RedirectUri, UriKind.RelativeOrAbsolute);
if (redirectUri.IsAbsoluteUri)
{
ctx.AuthenticationTicket.Properties.RedirectUri = redirectUri.PathAndQuery;
}
//Sync user and the roles to EPiServer in the background
ServiceLocator.Current.GetInstance<ISynchronizingUserService>().
SynchronizeAsync(ctx.AuthenticationTicket.Identity);
return Task.FromResult(0);
}
}
});
app.UseStageMarker(PipelineStage.Authenticate);
app.Map(logoutPath, map =>
{
map.Run(ctx =>
{
ctx.Authentication.SignOut();
return Task.FromResult(0);
});
});
}
Global.ascx.cs
routes.MapRoute(
"Adfs",
"Adfs",
new { controller = "AdfsController", action = "index" }
);
In my web.config I have the following set
<authentication mode="None"/>
<membership>
<providers>
<clear/>
</providers>
</membership>
<roleManager enabled="false">
<providers>
<clear/>
</providers>
</roleManager>
<episerver.framework createDatabaseSchema="true" updateDatabaseSchema="true">
<securityEntity>
<providers>
<add name="SynchronizingProvider" type="EPiServer.Security.SynchronizingRolesSecurityEntityProvider, EPiServer"/>
</providers>
</securityEntity>
I've then created my own MVC login to then redirect to each Azure tenant
public class AdfsController : Controller
{
// GET: Adfs
public ActionResult Index()
{
var pageRouteHelper = EPiServer.ServiceLocation.ServiceLocator.Current.GetInstance<IPageRouteHelper>();
PageData currentPage = pageRouteHelper.Page;
return View(currentPage);
}
public ActionResult AdfsLogin(string tenantContext, string returnUrl)
{
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = returnUrl ?? "/" }, tenantContext);
return Redirect(returnUrl);
}
}
And then in my View
#{
using (Html.BeginForm("AdfsLogin", "Adfs", new { ReturnUrl = "/episerver", tenantContext = "tenant_1" }))
{
#Html.AntiForgeryToken()
<ol class="clearfix">
<li>
<input type="submit" value="tenant 1" id="btnAd1" class="epi-button-child-item" />
</li>
</ol>
}
using (Html.BeginForm("AdfsLogin", "Adfs", new { ReturnUrl = "/episerver", tenantContext = "tenant_2" }))
{
#Html.AntiForgeryToken()
<ol class="clearfix">
<li>
<input type="submit" value="tenant 2" id="btnAd2" class="epi-button-child-item" />
</li>
</ol>
}
Has anyone else had this problem? or know how to resolve it

How to set common Wreply for multiple ADFS endpoints with OWIN?

I want to configure ADFS endpoints in my asp.net app at runtime.
There is a problem: if I declare single callback method for multiple endpoints then I have exception:
Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10501: Signature validation failed. Unable to match keys:
kid: '[PII is hidden]',
token: '[PII is hidden]'.
If I will hard-code callbacks (Wreply) for each endpoint then all works, but this is not my case.
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
var federationEndpoints = Service.ListActiveFederationEndpoints();
if (federationEndpoints.Any())
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
var endpointOptions = new List<WsFederationAuthenticationOptions>();
foreach (var endpoint in federationEndpoints)
{
string metadata = endpoint.ServerUri;
string wtrealm = endpoint.RelyingPartyIdentifier;
endpointOptions.Add(new WsFederationAuthenticationOptions
{
Wtrealm = wtrealm,
MetadataAddress = metadata,
AuthenticationType = endpoint.Name
});
}
app.Map("/FederationAuth", configuration =>
{
endpointOptions.ForEach(o => app.UseWsFederationAuthentication(o));
});
}
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
}
}
Login and common callback (Wreply) in FederationAuthController
[AllowAnonymous]
public void ExternalLogin(string endpointName)
{
var ctx = Request.GetOwinContext();
ctx.Authentication.Challenge(
new AuthenticationProperties { RedirectUri = Url.Action("LoginCallbackAdfs", "FederationAuth") },
endpointName);
}
public ActionResult LoginCallbackAdfs()
{
var ctx = System.Web.HttpContext.Current;
var claimsIdentity = User.Identity as ClaimsIdentity;
var sessionIdentity = Service.LoginByClaims(claimsIdentity);
return this.RedirectToAction("Index", "SinglePage");
}
I've read many answers for configuring hard-coded multiple ADFS endpoints in Web.config but is there possibility to configure enpoints at runtime?
Thank you!
Wreply should be unique and set for each federation middleware during pipeline building. I made unique Wreply including endpoint name as callback parameter.
Startup.cs
public void Configuration(IAppBuilder app)
{
var federationChannels = Service.GetFederationChannels();
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.SetDefaultSignInAsAuthenticationType(CookieAuth.AuthenticationType);
foreach (var channel in federationChannels)
{
var metadata = channel.Metadata;
var wtrealm = channel.Wtrealm ;
var host = GetServerAddress();
var wreply = $"{host}FederationLogin/channel={channel.Id}";
app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
{
Wtrealm = wtrealm,
MetadataAddress = metadata,
AuthenticationType = channel.Id,
Wreply = wreply,
SignOutWreply = host
});
}
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
}
Controller
public ActionResult FederationLogin(string channel)
{
....
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties(), channel);
....
}

Custom Table names in Identity 2.0, User.IsInRole() not working

I tried to rename the tables with the following code:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("Users").Property(p => p.Id).HasColumnName("UserId");
modelBuilder.Entity<ApplicationUser>().ToTable("Users").Property(p => p.Id).HasColumnName("UserId");
modelBuilder.Entity<IdentityRole>().ToTable("Roles");
modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
}
It worked. The table names have been renamed properly, and data seems to be getting inserted in the proper places.
However, The User.IsInRole("rolestring") method doesn't work. It returns false all the time.
If I remove the above code, everything works fine.
What am I missing?
Update:
On your Startup class, when configure the OAuthAuthorizationServerOptions, on Provider property you should have a custom class that inherits from OAuthAuthorizationServerProvider. In the example below, the CustomAuthorizationServerProvider class:
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new CustomAuthorizationServerProvider()
};
And this is code of CustomAuthorizationServerProvider, where you have to override GrantResourceOwnerCredentials:
public class CustomAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
...
context.Validated();
return Task.FromResult<object>(null);
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = context.OwinContext.Get<string>("as:clientAllowedOrigin");
if (allowedOrigin == null) allowedOrigin = "*";
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
IdentityUser user;
using (AuthRepository repository = new AuthRepository())
{
user = await repository.FindUser(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect");
return;
}
}
UserManager<IdentityUser> userManager = new UserManager<IdentityUser>(new UserStore<IdentityUser>(new AuthDBContext()));
ClaimsIdentity identity = await userManager.CreateIdentityAsync(user, context.Options.AuthenticationType);
AuthenticationProperties properties = new AuthenticationProperties(new Dictionary<string, string>
{
{
"as:client_id", context.ClientId ?? string.Empty
},
{
"userName", context.UserName
},
{
"roles",String.Join(",", (IEnumerable<IdentityUserRole>) user.Roles.ToArray())
}
});
AuthenticationTicket ticket = new AuthenticationTicket(identity, properties);
context.Validated(ticket);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
}
Note: AuthDBContext is the same class you are declaring your OnModelCreating method.
So, reviewing the code above, you'll check that user roles are inserted in AuthenticationProperties dictionary
{
"roles",String.Join(",", (IEnumerable<IdentityUserRole>) user.Roles.ToArray())
}
and then they are inserted in the ticket with the ClaimsIdentity object of the current user.
AuthenticationTicket ticket = new AuthenticationTicket(identity, properties);
Once you've fixed this, you only have to add the [Authorize] attribute in your actions and/or controllers like this:
[Authorize(Roles = "Admin")]
Or check in your controller actions the equivalent:
ActionContext.RequestContext.Principal.IsInRole("Admin")

ServiceStack RequiredRole is not asking for role to access

I'm trying to define a permissions for a ServiceStack Service which only can access the Admin Role for example and I have this Service with the RequireRole attribute but it seems does not work because I can access the service as a USER .
[Authenticate]
[RequiredRole("Admin")]
public class HelloService : Service
{
public const string HelloServiceCounterKey = "HelloServiceCounter";
public object Any(HelloRequest request)
{
var userSession = SessionAs<AppHost.CustomUserSession>();
Session.Set(HelloServiceCounterKey, Session.Get<int>(HelloServiceCounterKey) + 1);
var roles = string.Join(", ", userSession.Roles.ToArray());
return new HelloResponse { Result = "Hello, " + request.Name + ", your role(s): " + roles };
}
}
AccountController.cs
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
try
{
if (!WebSecurity.UserExists("Admin"))
WebSecurity.CreateUserAndAccount("admin", "abc");
var authService = AppHostBase.Resolve<AuthService>();
authService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var response = authService.Authenticate(new Auth
{
UserName = model.UserName,
Password = model.Password,
RememberMe = model.RememberMe
});
// add ASP.NET auth cookie
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
return RedirectToLocal(returnUrl);
}
catch (HttpError)
{
}
}
and Here's my AppHost.cs
public override void Configure(Funq.Container container)
{
/*Register storage for User Session */
container.Register<ICacheClient>(new MemoryCacheClient()); /*Tipo Base de MemoryCacheClient es ICacheClient*/
container.Register<ISessionFactory>(c => new SessionFactory(c.Resolve<ICacheClient>())); /*Tipo Base de SessionFactory es ISessionFactory*/
Plugins.Add(new AuthFeature(
() => new CustomUserSession(),
new[] { new CustomCredentialsAuthProvider() }
));
Plugins.Add(new SessionFeature());
Routes
.Add<HelloService>("/hello")
.Add<HelloService>("/hello/{Name*}");
//Set JSON web services to return idiomatic JSON camelCase properties
ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;
container.Register(new TodoRepository());
//Set MVC to use the same Funq IOC as ServiceStack
ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));
}
The wiki states:
As with Authenticate, you can mark services (instead of DTO) with
RequiredPermission attribute, too.
It does NOT state whether you can use the RequiredRole attribute with a service, so I think you cannot and looking at the comments in source it does seem to target just requestDTO object.

Resources