Web API has no session - need to check if user is authenticated - c#

I'm creating my first WebAPI project, and have hit my first snag. It seems that because the WebAPI model is stateless, I have no Session available to me. So, my attempt to add a session variable when logging in, has failed.
public static void CreateSession(int userId, string firstName, string surname, int timezoneOffset, string timezoneName)
{
// Create the object.
var session = new SessionToken
{
FirstName = firstName,
Surname = surname,
TimezoneName = timezoneName,
TimezoneOffset = timezoneOffset,
UserID = userId
};
// Is there an existing session?
var existing = HttpContext.Current.Session[SESSIONNAME];
// If so, we need to kill it and refresh it. Not sure why we would have this case though.
if (existing != null)
HttpContext.Current.Session.Remove(SESSIONNAME);
// Create the session.
HttpContext.Current.Session.Add(SESSIONNAME, session);
}
Session is null, and this is because of the stateless model used by WebAPI.
How can I achieve this with Web API? How can I have something to check and query to see if the current user is valid? My session would normally hold some items such as the chaps name, to render on the layout screen - but it looks like that isn't possible right now.

The recommended approach is using stateless authentication and authorization with tokens.
Since some years, it's very easy to configure your WebAPI to integrate OAuth2 workflow using an OWIN middleware.
Learn how following this tutorial.
What you call session items, in OAuth2 you talk about claims.

Related

How to properly access HTTP Headers from your controller? (.NET Web App)

I am currently developing a .NET Web App (MVC), and it is designed such that the user logs into the app in another web app, then the IIS passes control to my web app (I call it SP). SP then needs to access headers passed to it containing user information passed from the login page. These fields are then used to add the user to a database for logging purposes. This behavior is called in the constructor from the main controller of the Web App: HomeController because I would like it to run whenever a user accesses the page.
This is my current implementation:
public HomeController()
{
try
{
string ID = Request.Headers.Get("CN userName");
if (ID.Length > 3)
{
try
{
ID = ID.Substring(3, 3);
}
catch
{
ID = ID.Substring(0, 3);
}
}
string firstName = Request.Headers.Get("X-First Name");
string lastName = Request.Headers.Get("X-Last Name");
string email = Request.Headers.Get("X-Mail");
currUser = new User(ID, firstName, lastName, email, ""); }
catch (Exception e)
{
currUser = new User(/*Create Default User*/);
}
}
The User constructor handles methods needed to manage the User after creation. However, this currently throws an error when deployed when it attempts to access any of the headers. I do not have a lot of experience working with headers so I spent hours attempting to find a solution online, but nothing I tried accomplished what I needed it to. I would appreciate assistance in solving this issue and implementing this behavior properly.
I don't think you should do this in a controllers constructor (not sure it's safe either).
It's probably better suited to an Filter, which will make it far easier to reuse.

ASP.NET Boilerplate Allow Self-Provisioning Tenant Registration

so im trying to create a SaaS application with ASP.NET Boilerplate, and i come into some problem as follows:
As i observe the framework, i noted that the "RegisterAsync" function in UserRegistrationManager create user based on the currently active tenant. It means if i currently log in on tenant '1', then when i register new user, the new user will have tenantId '1'. On the other hand, when i currently not logged in, if i register a new user, the app will show exception 'cannot register host user'.
public async Task<User> RegisterAsync(string name, string surname, string emailAddress, string phoneNumber, string userName, string plainPassword, bool isEmailConfirmed)
{
CheckForTenant();
var tenant = await GetActiveTenantAsync();
var user = new User
{
TenantId = tenant.Id,
Name = name,
Surname = surname,
EmailAddress = emailAddress,
PhoneNumber = phoneNumber,
IsActive = true,
UserName = userName,
IsEmailConfirmed = isEmailConfirmed,
Roles = new List<UserRole>()
};
return user;
}
private void CheckForTenant()
{
if (!AbpSession.TenantId.HasValue)
{
throw new InvalidOperationException("Can not register host users!");
}
}
The application that i want to build requires the function for new user to be able to sign up along with free trial and then paid subscription. So i think that the new user should be able to create tenant by themself. So if the new user register, they will be forced to create new tenant before they can do any other thing in the app.
The problem is that the tenantId column in User table cannot be null, so i can register without tenant. Im thinking of assign all newly created user to 'Default' tenant at first, but i think that this was not the best practices.
Is there any way to overcome this problem or any references about that? Thanks in advance!
Based on my empirical SaaS Application development experience, a typical Self-Signup flow in Multi-Tenant applications would be like the one given below
User opts to self-signin
Allow the user to pick a subscription plan (most likely a trial plan)
Get the Company Name (tenant name) as part of the signup flow
Create a new tenant that has the subscription (2)
Add the signup user as the administrator for that tenant
In case of a trial plan, set up the suitable request handler to keep validating if the tenant has crossed the subscribed number of trial days, in that case, force redirect to payment page or signout
If the user has opted to Signup for a paid subscription (during signup), after provisioning the tenant go to the payment page. Once payment succeeds, capture the transactionid and allow the user to login and use the application.
The flow that you wanted to be using is straightforward
Build a custom self-signup process, obtain the company name (Tenant Name)
Also capture the emailid of the user that is performing the sign-up
Create the tenant based on info from (1)
Set the administrator for the tenant based on the info from (2)
All your API calls should be working fine.
Note
Have a separate Self-Signup Service like (TenantSelfRegistrationService) so that you can allow anonymous access to that service.
In terms of security, set captcha and set rate-limits or CSRF Tokens etc to enforce security in the signup process.
Hope this clarifies
I looked at the code and the documentation and I think you should never allow an unknown user to create new tenants. This should happen by a person who has the correct authorization to create tenants. This is a user that exists in the host tenant.
You as admin in the host tenant need to create tenant for somebody else and add them as admin for that tenant.
Registering users is then done through the normal way with the register webpage running for that tenant.
How to do that, I leave to you to figure out with the documentation of boilerplate itself! Documentation

Publishing tweets from C# Windows service using Tweetinvi or similar

I am looking into publishing some service status updates on Twitter using Tweetinvi, which seems like a good library for doing that sort of thing, but I am just starting out looking into this so using it is not set in stone.
However, one thing my research has not yielded yet, is an obvious way to handle Twitter authentication in what is essentially a headless service. I have created an app with Twitter, so I have my consumer key and secret, and I can do the "app only" auth to request user info, get their followers etc., but of course I have no right to publish tweets.
So my ambition is (once this is out of beta) to create a proper twitter account, somehow have the service authenticate towards that account, and then publish status updates from the general service at defined intervals. It is a fairly simple idea.
Of course, I can do something like the PIN based authentication mentioned here:
https://github.com/linvi/tweetinvi/wiki/Authentication
I can run that manually, get the PIN code, and proceed with the workflow. But will this require reauthentication at regular intervals, or will it basically be valid "forever"? I am looking for a way to make this as automatic as possible, and having to redo the auth every x hours is a huge dent in this dream, if not a showstopper.
Of course I will have the password for the twitter account used to publish statuses, but I don't see a way to do a good old fashioned login without manual user intervention - what options do I have?
This behavior is by design. Twitter uses OAuth, which is a protocol with the purpose of allowing a user to authorize an application. This is good for the user because otherwise, you or anyone else can perform actions on their behalf without them knowing.
With that in mind, the only way to do this is to have the user explicitly authorize your app. Here's an example of how to do this with LINQ to Twitter, which I wrote, using ASP.NET MVC. When the user visit's your page, you can have a button that re-directs them to the OAuthController below to the BeginAsync action.
using System;
using System.Configuration;
using System.Linq;
using System.Threading.Tasks;
using System.Web.Mvc;
using LinqToTwitter;
namespace MvcDemo.Controllers
{
public class OAuthController : AsyncController
{
public ActionResult Index()
{
return View();
}
public async Task<ActionResult> BeginAsync()
{
//var auth = new MvcSignInAuthorizer
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"]
}
};
string twitterCallbackUrl = Request.Url.ToString().Replace("Begin", "Complete");
return await auth.BeginAuthorizationAsync(new Uri(twitterCallbackUrl));
}
public async Task<ActionResult> CompleteAsync()
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore()
};
await auth.CompleteAuthorizeAsync(Request.Url);
// This is how you access credentials after authorization.
// The oauthToken and oauthTokenSecret do not expire.
// You can use the userID to associate the credentials with the user.
// You can save credentials any way you want - database,
// isolated storage, etc. - it's up to you.
// You can retrieve and load all 4 credentials on subsequent
// queries to avoid the need to re-authorize.
// When you've loaded all 4 credentials, LINQ to Twitter will let
// you make queries without re-authorizing.
//
//var credentials = auth.CredentialStore;
//string oauthToken = credentials.OAuthToken;
//string oauthTokenSecret = credentials.OAuthTokenSecret;
//string screenName = credentials.ScreenName;
//ulong userID = credentials.UserID;
//
return RedirectToAction("Index", "Home");
}
}
}
After the user authorizes your application, Twitter redirects them back to the CompleteAsync method. Notice the comments on how to extract values from the auth.CredentialStore. Save those in your DB and then retrieve them in your service to make calls on the user's behalf.
Those credentials don't change, but the user can possibly de-authorize your application at some time in the future - at which time you'll need to get them to authorize again. You can get the entire sample code at the LINQ to Twitter ASP.NET Samples page.

Generating an Identity User with Roles (From Web API to MVC Application)

Currently developing a couple of applications (MVC and Web API) where my MVC application will send the request to the API to get authenticated and "login". I've got it working so that all my MVC application has to do is store the bearer token from the Web API and attach it anytime it needs to make a request for data.
At this point in the program we are looking to start working with Authorization and some security trimming to limit which users can make certain requests to the API and which users are able to see certain pages on the MVC application. In order to do this on both ends I need to get the Roles from my API and impersonate the Identity user on the MVC side since they are technically already logged in. My problem right now is probably kind of simple, but I can't figure out how to declare the Roles when I generate an identity user. Right now I just need a test case that we can explicitly declare and then I can grab it later once we start passing Roles from the API.
Any idea how to make a functioning example out of this with Roles?
private IdentityUser GenerateIdentityUser(string IdNum, string userN)
{
var newUser = new IdentityUser
{
Id = IdNum,
UserName = userN,
// Roles =
SecurityStamp = DateTime.Now.Ticks.ToString()
};
return newUser;
}
The Roles property in the IdentityUser has a private setter (see codeplex source code). The constructor for IdentityUser always creates an empty list of roles, so that it won't be null.
To set a role you'll need to add the following line after initializing your newUser object:
newUser.Roles.Add(new IdentityUserRole {UserId = newUser.Id, RoleId = "your role id"});

Session usage in WCF service

In my wcf project, I want to store some user information(userid or something) as we use asp.net session.After logging in, the userid will store in session
and we can retrieve it for other service.I found we can use httpcontext.current.session in wcf but that one is only support for wcf hosted in IIS.
My wcf service will be hosted in window service.Is there any way to do? Is there any variable or function in wcf to get that features?
Please guide me the right way.Thanks for your help.
//For example
//LogOnWCFService
public Boolean LogOn(string userID, string PWD)
{
currentUserID = userID;
HttpContext.Current.Session.Add("UserID",userID);
return true;
}
//ProcessWCFService
public void Process()
{
string userid = HttpContext.Current.Session["UserID"].ToString();
if(userid == 1)
{
//Do Something
}
}
I would avoid the use of sessions with WCF, espescially if you want to use the session data over different Service calls.
A better approach would be to implement your own session management. The LogOnService could create an unique sesion ID after a successfull logon and return it to the client. The session ID could be persisted together with additional informations (UserID etc.). All other services then include this session ID in every method call to identitfy itself.
nSess = logscv.LogOn(UserID)....procsvc.Process(nSess)

Categories