Adding RequestFilter data to Context (Request Scope), Retrieve in Service - authentication

I implemented Basic Auth for my services. Since ServiceStack's AuthFeature is strongly coupled with the session concept, I implemented a custom RequestFilter that performs stateless basic auth (credentials go in, on every request). Our auth strategy internally contemplates roles and permissions.
Besides authentication, we need to enforce authorization (e.g., user is manipulating a product that he owns). We are using FluentValidation, for all service validations.
Authorization validations include cross checking auth data with request parameters. Question is, where should I place the auth data produced in the BasicAuthRequestFilter? Should I key value pair it in cache, associating, for instance, RequestContext (or any other object that uniquely identifies the request scope) with an Authentication object?
I could just plug the AuthData in the Request Dto, which is available directly at the RequestFilter, however this would mess up our service contract design. We define dtos in a separate DLL, where only service input/output details are defined.
Any suggestions?
Thanks in advance.

I too use my own custom authentication mechanism and make custom role information available to my service. I do this by authenticating the request in a custom ServiceRunner which can then pass the information directly to my custom Service base. This ultimately means accessing information about the users permissions is exceptionally easy.
Create a custom ServiceRunner:
public class ServiceRunner<T> : ServiceStack.ServiceHost.ServiceRunner<T>
{
public ServiceRunner(IAppHost appHost, ActionContext actionContext) : base(appHost, actionContext)
{
}
public override object Execute(IRequestContext requestContext, object instance, T request)
{
// Check if the instance is of type AuthenticatedBase
var authenticatedBase = instance as AuthenticatedBase;
// If the request is not using the AuthenticatedBase, then allow it to run, as normal.
if(authenticatedBase == null)
return base.Execute(requestContext, instance, request);
/*
* Authentication required. Do you authorization check here.
* i.e.
* var authorization = requestContext.GetHeader("Authorization");
* bool authorised = ... some condition;
*/
/* You have access to your service base so if you injected the Db connection
* in you app config using IoC, then you can access the Db here.
* i.e.
* authenticatedBase.Db
*/
/*
* Not authorized?
* throw new UnauthorizedException();
*/
/*
* If authorized:
* Then simple set the details about their permissions
*/
authenticatedBase.AuthData = new AuthData { Id = 123, Roles = [], Username = "" };
// Pass back the authenticated base
return base.Execute(requestContext, authenticatedBase, request);
}
}
Configure you application to use it by adding this to your AppHost:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new ServiceRunner<TRequest>(this, actionContext);
}
Create a custom class to hold your auth data i.e. the user session information, such as:
public class AuthData
{
public int Id { get; set; }
public string Username { get; set; }
public int[] Roles { get; set; }
...
}
Then create a custom service base
public class AuthenticatedBase : Service
{
public AuthData AuthData { get; set; }
}
To then use the AuthData in the service is simply a case of extending AuthenticatedBase.
public class CustomerHandler : AuthenticatedBase
{
public object Get(ListCustomers request)
{
// You can access the AuthData now in the handler
var roles = AuthData.Role; // Check they have the role required to list customers
...
}
}
You are probably wondering why go to all the trouble of using the ServiceRunner over a RequestFilter but the main advantage is it gives direct access to the instance of the Service base, which isn't available to a RequestFilter.
The RequestFilters are run before the Service base is instantiated, so you can't populate it from there. See order of operations for more information.
By having access to the ServiceBase we can populate values (in this case AuthData) and we have access to our injected dependancies such as the database connection.
I hope you find this useful. You should be able to copy most of your existing RequestFilter into the service runner. If you need any further help with this just let me know.
Update to support Attributes:
Since you are unable to avoid using the attribute method to handle your authentication needs you can still use this method:
Continue doing your authentication and access filtering the way you were before.
In your existing authentication mechanism use req.Items.Add to set the AuthData i.e. Where req is your request object
req.Items.Add("AuthData", new AuthData { Username = "", Roles = [] ... });
Then access your AuthData item in your service base:
public class AuthenticatedBase : Service
{
public AuthData AuthData
{
get { return base.Request.Items["AuthData"] as AuthData; }
}
}

Related

Logging user info and update operations from REST / EJB service

I need to log all update operations from my rest resources and store to a Database log table.
The idea is to store info like:
logged user
operation description about updated / saved entity
updated fields and reference key
My application is Java EE8 compatible, it uses REST / EJB and CDI stuff.
At first I thought of dealing all this stuff on EJB side, however the exposed services don't need to have logged user on the method signature, so adding it would result on a forcing..
Is there any way to send user information, that is normally retrieved by webrequest (we use a session token model authentication) and inject through EJB ?
If your session management is setup correctly, you can just inject the session context via:
#Resource
SessionContext sessionContext;
Then:
sessionContext.getCallerPrincipal().getName()
is your logged in user.
As mentioned before, SessionContext.getCallerPrincipal().getName() doesn't work as authentication mechanism does not provide it.
After some tries I found this:
On EJB side
#RequestScoped
public class UserInfo {
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
if (this.userId != null) throw new UncheckedException("cannot infer userid twice");
this.userId = userId;
}
}
On REST side
#Inject
UserInfo userInfo;
void userAuthenticated(...) {
String userId = ... // get userid from access token through **WebRequest** object
userInfo.setUserId(userId);
}
Side note
I honestly would have preferred to inject userid on UserInfo constructor but I was not allowed doing this as WebRequest object does not belong to EJB context
Alternative way
Move all the logging process to REST side by using a Response filter.
Example code:
#Provider
public class LoggingFilter implements ContainerResponseFilter {
#Context
HttpServletRequest webRequest;
#Context
ResourceInfo resinfo;
#Inject
LoggingService loggingService;
#Override
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) {
final Method resourceMethod = resinfo.getResourceMethod();
if (resourceMethod.isAnnotationPresent(Loggable.class) && containerResponseContext.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) {
// get all method's info and log to database ...
}
}

How can I get the user from my AuthorizationAttribute from within an ASPNETCORE 2.2 application?

I have created a custom attribute that I would like to decorate my api controller from within my ASPNETCORE angular application. I am able to set up my authentication as required and log into the application from the login. Then I decorate my api method with my custom attribute.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false)]
public class ManageAuditAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public List<Claim> Claims { get; set; }
public ManageAuditAttribute(String feature)
{
Feature = feature;
}
public bool IsAuthorized()
{
// TODO check there is a claim for the given feature
}
private String Feature { get; }
public void OnAuthorization(AuthorizationFilterContext context)
{
var accessor = (IHttpContextAccessor)context.HttpContext.RequestServices.GetService(typeof(IHttpContextAccessor));
var name = context.HttpContext.User.FindFirst(ClaimTypes.Email); //NULL
var user = context.HttpContext.User; // NULL
var userName = Thread.CurrentPrincipal.Identity.Name; // NULL
}
}
Before saying that claims are not used this way I would add that I need to fit this into a legacy system that has a list of allowed features. I am adding those features to the user as claims and checking the claim exists for each user. The value for the actual claim is the name of the application that the user needs the claim for.
I could easily add these as a custom list to my custom identity user which might be more fitting however, I still need to access my user.
I can get the user but the name is always null and my claims list is empty as well. It is as if I am not logged in at all. Even after logging in.
For retrieving name, you should pass ClaimTypes.Name instead of ClaimTypes.Email like
var user = context.HttpContext.User.FindFirst(ClaimTypes.Name);
Or, you could retrieve by HttpContext.User.Identity.Name like
var userName = context.HttpContext.User.Identity.Name;
I have solved you problem by adding:
app.UseAuthentication();
in Startup.cs.

Where do I handle custom authentication and authorization in webapi?

NOTE: I have many questions littered in the code comments below. I need answers to those as well.
I have read (among many others) the following articles:
http://blogs.msdn.com/b/hongmeig1/archive/2012/05/11/how-to-write-a-custom-parameter-binding-to-construct-an-object-either-from-body-or-from-uri-s-query.aspx
http://blogs.msdn.com/b/jmstall/archive/2012/05/11/webapi-parameter-binding-under-the-hood.aspx
I would like for my web api to have authentication sent in the header using the Authorization header. I would like this header to be populated into a c# class called AuthenticationToken. Then when I am doing parameter binding I would like to retreive this previously created AuthenticationToken object and pass it on to my controller action. For example, if I have the following controller
public class MyServiceController : ApiController {
readonly ISecurityService _security;
readonly IMyService _myService;
// constructor values are injected
public MyServiceController(ISecurityService security, IMyService myService) {
_security = security;
_myService = myService;
}
public SomeData GetASpecificItem(AuthenticationToken token, int id) {
if (_security.IsAuthorized(token, Permissions.Read)) {
return myService.DoStuffToGetSomeData(token);
} else {
var msg = new HttpResponseMessage(HttpStatusCode.Forbidden);
throw new HttpResponseException(msg);
}
}
}
and the following parameter binding class
public class AuthenticationTokenParameterBinding
: HttpParameterBinding { // do I need to inherit from a different class?
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,
HttpActionContext actionContext,
CancellationToken cancellationToken) {
try {
AuthenticationToken token; // UPDATED: how can i get this from the data
// available from inside this method?
SetValue(actionContext, token);
// is this the correct task to return on successfull parameter binding?
return base.ExecuteBindingAsyn(metadataProvider, actionContext, cancellationToken);
} catch {
return Task<HttpResponseMessage>.Factory.StartNew(() => {
var hpm = new HttpResponseMessage(HttpStatusCode.Unauthorized);
hpm.Headers.Add("WWW-Authenticate","MyCustomScheme");
return hpm;
});
}
}
}
If these two are implemented correctly, then the controller will automatically get the AuthenticationToken instance that was created during authorization.
I do not know where to authenticate ahead of this process. Nor do I know how to pass an object between authentication and authorization.
UPDATE:
I can't use a custom AuthorizeAttribute because authorization may be against an object:
public SaveResponse Save(AuthenticationToken user, SomeObjectThatNeedsToBeSaved obj) {
// NOTE: permissions are checked between the object and the user, not a role
if (_security.IsAuthorized(user, obj, Permission.Modify, Permission.Create)) {
// NOTE: other permissions we don't know about may need to be checked in the service call
return new SaveResponse {
Success = ISomeService.Save(user, obj); // bool return value
}
} else {
// return 403 Forbidden }
}
I need to pass the token to the controller action, but I also need to authenticate the token before it gets passed to the controller. Since all of this is not necessarily role based, I don't see how I can authenticate from inside of a custom AuthorizeAttribute
I have used a custom AuthorizeAttribute to handle both authentication and authorization for Web API. This attribute works as a filter and will process the request before it gets to your Web API method. In the overridden OnAuthorize method you can return HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized) if authentication fails and HttpResponseMessage(System.Net.HttpStatusCode.Forbidden) if authorization fails so that the client can distinguish between both types of errors. In addition to the custom AuthorizeAttribute I implemented a custom MembershipProvider and RoleProvider to handle my specific security requirements and custom database schema.
I use basic authentication to pass the credentials for authorization. This puts the credentials in the header. To do this is pretty straight forward by using the beforeSend event handler of the JQuery ajax function. Here is an example of how to do this.
getAuthorizationHeader = function (username, password) {
var authType;
var up = $.base64.encode(username + ":" + password);
authType = "Basic " + up;
};
return authType;
};
$.ajax({
url: _url,
data: _data,
type: _type,
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", getAuthorizationHeader(username, password));
},
success: ajaxSuccessHandler,
error: ajaxErrHandler
});
This encodes the username/password that is sent in the header. Note that this is not enough security to rely on just the encoding as it is easy to decode. You still want to use HTTPS/SSL to make sure the information sent over the wire is secure.
On the Web API side you can make a custom AuthorizeAttribute that gets the credentials from the header, decodes them, and performs your authorization process. There is a separate AuthorizeAttribute used by the Web API as opposed to the controller. Be sure to use System.Web.Http.AuthorizeAttribute as your base class when creating your custom AuthorizeAttribute. They have different behaviors. The one for the controller will want to redirect to the logon page whereas the one for the Web API returns an HTTP code indicating success or failure. I return an HTTP code of Forbidden if authorization fails to distinguish a failure due to authorization as opposed to authentication so the client can react accordingly.
Here is an example method for getting the credentials from the header that can be used in the custom AuthorizeAttribute.
private bool GetUserNameAndPassword(HttpActionContext actionContext, out string username, out string password)
{
bool gotIt = false;
username = string.Empty;
password = string.Empty;
IEnumerable<string> headerVals;
if (actionContext.Request.Headers.TryGetValues("Authorization", out headerVals))
{
try
{
string authHeader = headerVals.FirstOrDefault();
char[] delims = { ' ' };
string[] authHeaderTokens = authHeader.Split(new char[] { ' ' });
if (authHeaderTokens[0].Contains("Basic"))
{
string decodedStr = SecurityHelper.DecodeFrom64(authHeaderTokens[1]);
string[] unpw = decodedStr.Split(new char[] { ':' });
username = unpw[0];
password = unpw[1];
}
gotIt = true;
}
catch { gotIt = false; }
}
return gotIt;
}
And here is the code for decoding the header data that is used in this method.
public static string DecodeFrom64(string encodedData)
{
byte[] encodedDataAsBytes
= System.Convert.FromBase64String(encodedData);
string returnValue =
System.Text.Encoding.ASCII.GetString(encodedDataAsBytes);
return returnValue;
}
Once you have the username and password you can perform your authorization process and return the appropriate HTTP code to the client for handling.
You could perform the a similar process with your custom token, or you can leverage the cookie that is passed back and forth if you do not want to keep the password/username stored in the client.

How to implement authorization combined with a custom username validation in wcf

I have a custom username/password validation in a WCF service. I followed the steps on this site to create this authentication.
I want to develop some kind of authorization based on the already validated credentials but don't know where to find this kind of information. I googled a lot and found lots of ways to regulate authorization but can't find a way to base this authorization on the custom username validation.
I am new to wcf and overwhelmed by all it's different kinds of methods.
Can someone provide me with some links where i can find information about this specific subject?
I have found this article to be a great summary of all the things WCF has to offer to support authorization. The article starts with the simplest implementation and then discusses each incremental step in complexity all the way to full blown claims based authorization.
Based on the information you provided regarding your specific situation, I would recommend that you create a custom implementation of IPrincipal, as illustrated in Figure 3 of the article I linked. I have included the code sample from the article here as well.
class CustomPrincipal : IPrincipal
{
IIdentity _identity;
string[] _roles;
Cache _cache = HttpRuntime.Cache;
public CustomPrincipal(IIdentity identity)
{
_identity = identity;
}
// helper method for easy access (without casting)
public static CustomPrincipal Current
{
get
{
return Thread.CurrentPrincipal as CustomPrincipal;
}
}
public IIdentity Identity
{
get { return _identity; }
}
// return all roles (custom property)
public string[] Roles
{
get
{
EnsureRoles();
return _roles;
}
}
// IPrincipal role check
public bool IsInRole(string role)
{
EnsureRoles();
return _roles.Contains(role);
}
// cache roles for subsequent requests
protected virtual void EnsureRoles()
{
// caching logic omitted – see the sample download
}
}
In the custom username and password validator referenced in your original post, you would simply populate an instance of the new IPrincipal and attach it to the static value Thread.CurrentPrincipal. This will allow you to then simply decorate any methods you wish to control access to by using the PrincipalPermission attribute as illustrated below. This code sample is also Figure 1 from the article I linked.
class Service : IService {
// only 'users' role member can call this method
[PrincipalPermission(SecurityAction.Demand, Role = 'users')]
public string[] GetRoles(string username) {
// only administrators can retrieve the role information for other users
if (ServiceSecurityContext.Current.PrimaryIdentity.Name != username) {
if (Thread.CurrentPrincipal.IsInRole('administrators')) {
...
}
else {
// access denied
throw new SecurityException();
}
}
}
}

Spring MVC 3.1 How to access HttpSession in Custom Authentication Provider (which implements AuthenticationProvider)

My application calls a web service during the Authentication process (as shown in code below).
How can I save some information in HttpSession during this process?
This information like customer-account-number will be used in various other places in the application after the user is logged in.
Is it possible to pass HttpSession parameter to the MyServiceManager's static login method?
public class MyAuthenticationManager implements AuthenticationProvider {
#Override
public boolean supports(Class<? extends Object> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
#Override
public Authentication authenticate(Authentication authentication) {
//MyServiceManager.login - makes a call to web service
if(MyServiceManager.login(authentication.getName(), authentication.getCredentials().toString(), XXX_HTTP_SESSION_XXX))
{
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority> ();
authorities.add(new GrantedAuthorityImpl("ROLE_USER"));
authorities.add(new GrantedAuthorityImpl("ROLE_SUPERVISOR"));
return new UsernamePasswordAuthenticationToken(authentication.getName(), authentication.getCredentials(),authorities);
}
else
{
return null;
}
}
}
After breaking a lot of head on this issue, I was able to achive the objective using following work around.
Getting hold of session is really not feasible in following method
public Authentication authenticate(Authentication authentication)
I created a class
import java.security.Principal;
public class UserInfo implements Principal{
private String customerId;
private String accountNumber;
private String name;
}
The information which I wanted to store in session (like customerId, accountNumber etc), I saved it in userInfo object.
and this object was passed to UsernamePasswordAuthenticationToken
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new GrantedAuthorityImpl("ROLE_USER"));
authorities.add(new GrantedAuthorityImpl("ROLE_SUPERVISOR"));
return new UsernamePasswordAuthenticationToken(**userInfo**, authentication.getCredentials(),authorities);
This information is readily available in the user's session using
(UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
I home this is a good enough way to tackle the problem.
We can do this by:
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession session= attr.getRequest().getSession(false);
I recommend false as it is assumed that no one without valid session should be inside this method.