What should the return object of ServiceStack Authorize method be? - servicestack

I am writing my own authorize provider for SAML2 authorization. To help me, I got a third party library to handle most of the SAML2 specification.
However this library is written for the ASP.NET HttpHandler interface where there is no return values for the ProcessRequest method.
With this library the method itself will not return anything, but takes care of most of my work of compressing the authentication request XML, creating the signature for the XML and telling the browser to redirect to SAML2 login page, with the correct attributes for the call. So it does a lot of work for me.
Some pseudo code:
public object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request)
{
...
AuthnRequest authnRequestXML = saml2Util.CreateAuthnRequestXML();
HttpResponseBase httpResponse = authService.Request.Response.OriginalResponse as HttpResponseBase;
// This takes care of signing, compression of the authnRequestXML and the redirect action
SAML2Library.SendAuthnRequestByHTTPRedirect(httpResponse, DestinationURL, authnRequestXML, certificatePrivateKey);
return ?;
}
Return null didn't work.
What should I set as the return value of the Authenticate method in this case?

To return a redirect response you can return a HttpResult e.g:
return HttpResult.Redirect(redirectUrl);

Related

How to add csrf token for immediate file upload for Spring Security 3.2?

I have been trying to add CSRF token for file uploads in my Spring application having spring security 3.2. The Spring Security CSRF documentation suggests we add MultipartFilter before the spring security filter so that temporary file upload becomes possible without spring security altogether (and hence without CSRF checking also). But wouldn't that be less secure?
Although, to have a working software atleast, I applied the above method but its not working. In error log it looks like the multipart filter is being triggered before the spring security filter, but still it IS going in the spring security filter and then to CSRF filter.
I am using <rich:fileUpload> with immediateUpload="true" to upload the file in the form.
May I get some help in applying this? It would be better if we can add the CSRF token itself instead of circumventing the security filter.
MultipartFilter does not stop the spring security filters from being invoked. But by putting it as the first filter in the filter chain, when there is a csrf token available in body as a param, it makes it possible for csrf token filter to extract the csrf token from body and verify it.
Short answer
You still neef to send csrf token but you can send it in body as a hidden param or in the url as a query param.
Note:
I dont have knowledge about the ui component you use but in your previous get request, you should have received a _csrf token as hidden param and you should include it as part of the url or as a hidden param in the multipart request.
If it is not clear, just to make a GET and POST request working without fileupload to understand the csrf flow
Alternative: Skip the csrf only for file upload
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.requireCsrfProtectionMatcher(new CustomRequiresCsrfMatcher())
.and()
......
}
private static final class CustomRequiresCsrfMatcher
implements RequestMatcher {
private final HashSet<String> allowedMethods = new HashSet<>(
Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
#Override
public boolean matches(HttpServletRequest request) {
String upload_url = "your file upload url";//update it
return !this.allowedMethods.contains(request.getMethod()) &&
!request.getRequestURL().toString().contains(upload_url);
}
}

Send additional parameters to social login

Is there anyway to save additional data to the session when doing a social login/signup?
I noticed that if I send returnUrl parameter to the SS OAuth endpoint (i.e. /auth/google?retunUrl=...) then this value gets saved to the session as ReferrerUrl so I am using that to embed data as url parameters. I would prefer to be able to write to the Meta collection when directing to the SS Auth endpoint and then later read it from the session.
I tried to follow the exact process of how this was being saved to the session but I found it quite confusing.
What is the best way to add additional meta data to a social login/signup?
Edit:
I am talking about making a GET request to /auth/google, /auth/facebook etc...
I have additional data I want to track with the signup the user has entered in the browser.
If I add code to OnAuthenticated then this doesn't solve problem as the data has gone out of scope of the browser. It has to be passed in the GET request to the auth endpoint or have some reference to match up.
Edit:
public class CustomUserSession : AuthUserSession
{
public override void OnCreated(IRequest httpReq)
{
this.Meta.Add("foo", "bar");
httpReq.SaveSession(this);
}
}
You can handle a callback with the OnAuthenticated() Session or Auth Events.

ASP.NET MVC5 OWIN rejects long URLs

I am creating an ASP.NET MVC5 action method that implements a password reset endpoint and accepts a click-through from an email message containing a token. My implementation uses OWIN middleware and closely resembles the ASP.NET Identity 2.1 samples application.
As per the samples application, the token is generated by UserManager and embedded into a URL that is sent to the user by email:
var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var encoded = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(token));
var uri = new Uri(Url.Link("ResetPasswordRoute", new { id = user.Id, token = encoded }));
The link in the email message targets an MVC endpoint that accepts the token parameter as one of its route segments:
[Route("reset-password/{id}/{token}"]
public async Task<ActionResult> PasswordResetAsync(int id, string token)
{
token = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(token));
// Implementation here
}
However, requests to this endpoint (using a URL generated in the above manner) fail with Bad Request - Invalid URL.
It appears that this failure occurs because the URL is too long. Specifically, if I truncate the token segment, it connects correctly to the MVC endpoint (although, of course, the token parameter is no longer valid). Specifically, the following truncated URL works ...
http://localhost:53717/account/reset-password/5/QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFE
... but it will fail if one additional character is added ...
http://localhost:53717/account/reset-password/5/QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFEf
I believe that the default IIS configuration setting for maxUrlLength should be compatible with what I am trying to do, but I have also tried explicitly setting it to a larger value, which did not solve the problem.
However, using Fiddler to examine the server response, I can see that the working URL generates a server response with the following header ...
Server: Microsoft-IIS/8.0
... whereas the longer URL is rejected with a response containing the following header ...
Server: Microsoft-HTTPAPI/2.0
This seems to imply that the URL is not being being rejected by IIS, but by a middleware component.
So, I am wondering what that component might be and how I might work around its effect.
Any suggestions please?
Many thanks,
Tim
Note: Although my implementation above Base64 encodes the token before using it in the URL, I have also experimented with the simpler approach used in the sample code, which relies on the URL encoding provided by UrlHelper.RouteUrl. Both techniques suffer from the same issue.
You should not be passing such long values in the application path of the URL as they are limited in length to something like 255 characters.
A slightly better alternative is to use a query string parameter instead:
http://localhost:53717/account/reset-password/5?token=QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFEf
That should be safe for at least 2000 characters (full URL) depending on the browser and IIS settings.
A more secure and scalable approach is to pass a token inside an HTTP header.

Servicestack - Call AuthProvider automatically

I would like to build my own AuthProvider. It should
Check if ss-id cookie is set and check for a valid session (this is
done automatically in servicestack)
If no valid session was found check a custom http-header (e.g. X-Api-Token)
If found a valid token create a new session
If not found a valid token send 401 Unauthorized
Basically this is the behaviour of the CredentialsAuthProvider except that I need to check for the X-Api-Token without making an explicit call to /auth/credentials. However the AuthProvider is never called automatically.
Any ideas how to get this done?
Edit: One idea was to use a request filter but there is still something missing:
this.GlobalRequestFilters.Add((request, response, arg3) =>
{
//If there is a valid ss-id cookie the it should have precedence and the request should be authenticated accordingly
if (!ValidatedViaSsIdCookie())
{
if (HeaderHasCorrectApiKey()) {
//Authenticate the current request by creating a new Session
AuthenticateRequest();
}
}
}
);
How to implement ValidatedViaSsIdCookie() and AuthenticateRequest()???
Edit: I don't think GlobalRequestFilters are the way to go because they will be executed after authentication... So if there is no valid session the filter is not executed at all and my Api key is never checked... Still searching for a better solution...
Regards
Dirk

Sending a GET request to the path given in the route

I am trying to call a REST service from a URL like this:
example.org/account/someusername
I have defined request and response DTOs.
[Route("/account/{UserName}", "GET")]
public class AccountRequest : IReturn<AccountResponse>
{
public string UserName { get; set; }
}
public class AccountResponse
{
public int Id { get; set; }
public string UserName { get; set; }
public string Bio { get; set; }
}
Calling the service:
JsonServiceClient client = new JsonServiceClient("http://example.org");
AccountRequest request = new AccountRequest { UserName = "me" };
AccountResponse response = client.Get(request);
However when I call the Get on the client, it doesn't respect the route. When I check the client instance in debugger, AsyncOneWayBaseUri value is example.org/json/asynconeway/. This part is irrelevant because it doesn't mean request is sent to this URL. I actually have no idea where it sends the request. I don't get any errors and all of my properties in response object is null.
What am I missing here?
Consume 3rd Party REST / HTTP Apis
ServiceStack's Service Clients are opinionated to call ServiceStack web services as they have support for ServiceStack's pre-defined routes, built-in Auth, auto-route generation, built-in Error Handling, etc.
To call 3rd Party REST / HTTP Apis you can use the HTTP Utils that come with ServiceStack.Text, which provide succinct, readable pleasant API's for common data access patterns around .NET's HttpWebRequest, e.g:
List<GithubRepo> repos = "https://api.github.com/users/{0}/repos".Fmt(user)
.GetJsonFromUrl()
.FromJson<List<GithubRepo>>();
Consuming ServiceStack services with C# .NET Service Clients
I'm not seeing the reported behavior, are you using the latest version of ServiceStack on the client?
One way to test the generated url that gets used (without making a service call) is to call the TRequest.ToUrl(method) extension method (that the Service Clients uss) directly, e.g.
AccountRequest request = new AccountRequest { UserName = "me" };
request.ToUrl("GET").Print(); // /account/me
The same auto-generated route was used when I tried calling it via the JsonServiceClient, e.g:
var client = new JsonServiceClient("http://example.org");
var response = client.Get(request); //calls http://example.org/account/me
Route URL used in ServiceStack's Service Clients
ServiceStack will attempt to use the most appropriate route that matches the values populated in the DTO and HTTP Method you're calling with, if there is no matching route it will fallback to the pre-defined routes.
By default the original predefined routes will be used:
/api/[xml|json|html|jsv|csv]/[syncreply|asynconeway]/[servicename]
But ServiceStack now also supports the shorter aliases of /reply and /oneway, e.g:
/api/[xml|json|html|jsv|csv]/[reply|oneway]/[servicename]
Which you can opt-in to use in the clients by setting the flag:
client.UseNewPredefinedRoutes = true;
it doesn't respect the route
Are you getting a 404 or a Handler not found exception?
Make sure whatever assembly your 'AccountService' class is in is added to the 'assembliesWithServices' parameter when configuring your AppHost. It sounds like the your Route is not being picked up by ServiceStack.
public MyAppHost() : base("my app", typeof(AccountService).Assembly) { }
What does your Service class look like?
Something like below should work (don't forget the Service interface)
public class AccountService : Service
{
public object Any(AccountRequest request)
{
return new AccountResponse() { UserName = request.UserName};
}
}
Servicestack supports a number of different data formats, such as JSON, XML, JSV, CSV, etc. and supports a number of different endpoints for accessing this data out of the box. Please find below details of the supported endpoints that has been taken from the formats section of the SS documentation.
The clients provided by ServiceStack use the default endpoint, not the restful endpoint to access the data. The data is still accessible restfully, you can test this by navigating to the restful URL in your browser.
Restful Endpoints
You can define which format should be used by adding ?format={format} to the end of the URL.
?format=json
?format=xml
?format=jsv
?format=csv
?format=htm
Example: http://www.servicestack.net/ServiceStack.Hello/servicestack/hello/World!?format=json
Alternatively ServiceStack also recognizes which format should be used with the Accept http header:
Accept: application/json
Accept: application/xml
As you can see, this approach only works with json and xml.
Default endpoint
/servicestack/[xml|json|html|jsv|csv]/[syncreply|asynconeway]/[servicename]
Examples:
/servicestack/xml/[syncreply|asynconeway]/[servicename] will be XML
/servicestack/json/[syncreply|asynconeway]/[servicename] will be JSON
SOAP endpoint
The SOAP endpoint only supports XML of course.
UPDATE
The ServiceStack clients cannot be used to connect to a non-ServiceStack web service because they rely on behavior which is specific to ServiceStack. Its probably best to use something like RestSharp or one of the many other available clients that allow you to interact with a restful web service.
Thanks everyone for their answers. C# client was sending the request to the right address from the start, I debugged it with Fiddler. Only I wasn't deserializing it properly.
Account object was in the data property of the response, not the response itself. The client is good at working with REST services even if they are not built with ServiceStack. It is pretty cool.

Resources