I'm working on an AWS project. We want to be able to issue STS temporary security credentials, with limited permissions, in order to access AWS services. We're working in .Net Core with C#.
We're using STS AssumeRoleAsync(), which is the .Net SDK's method for using the AWS AssumeRole action, to generate these credentials. The response from the call to AssumeRoleAsync() is an AssumeRoleResponse object, which is comprised in part of an AssumeRoleUser object and a Credentials object. One of the properties of AssumedRoleUser is AssumedRoleId, which is in the form of role-id:role-session-name.
We have a Lambda function which handles calling AssumeRoleAsync and returning the generated credentials in the form of a JSON object. That Lambda function is called via an API Gateway method.
All of this is working fine. The above was just to set the scene.
The next thing we want to be able to do is to use the STS temporary credentials to make other calls into AWS services. When that happens, we want be able to use GetCallerIdentity() to retrieve the AssumedRoleId for the person to whom the credentials were issued. In particular, the role-session-name is of interest to us.
So to try to accomplish this, I created another Lambda function behind another API Gateway method. I set this API Gateway method to use AWS_IAM authorization in its Method Request configuration. In its Integration Request, I configured it to Invoke with caller credentials. The Lambda function simply accepts the incoming request and calls GetCallerIdentity() and returns the result. I used the credentials returned from the previous AssumeRoleAsync() call in the request's authorization header.
Based on the information found in the docs for GetCallerIdentity and in the Principal Table to which that page refers, I expect to receive the following items in response from the GetCallerIdentity() call:
Account
Arn
UserId (this is the important bit for this discussion)
The UserId should be in the form of role-id:caller-specified-role-name, exactly the same form in which the AssumedRoleId from the call to AssumeRoleAsync was returned. That would allow me to get the caller-specified-role-name and do what we need to do with it.
But that isn't what is returned in the UserId property of the response from GetCallerIdentity().
Instead, all that the UserId property contains is the role-id — it completely omits the essential caller-specified-role-name.
Has anyone else seen this behavior? Am I overlooking something simple? Could this be a bug in the response from GetCallerIdentity?
I'm using the following Amazon SDK components and versions to make these various calls:
Amazon.Lambda.Core/1.0.0
Amazon.Lambda.Serialization.Json/1.1.0
AWSSDK.Core/3.3.14
AWSSDK.Lambda/3.3.6.2
AWSSDK.SecurityToken/3.3.1.9
Thanks for any help you can suggest!
Derek
Related
I'm trying to call multiple attributes via the graph api including the authentication email methods.
However when i try to select the authentication attribute, i always receive a null value.
Calling it directly works fine, however that way i need to call the graph api a second time to get all other attributes.
My Call looks something like this.
await _graphClient.Users[userId].Request()
.Select($"displayName,authentication,otherMails,identities).GetAsync();
This way the authentication attributes just shows a null value,
even though the UserAuthenticationMethod.ReadWrite.All is set for the api
Using this works just fine
await _graphClient.Users[userId].Authentication
.EmailMethods["3ddfcfc8-9383-446f-83cc-3ab9be4be18f"].Request().GetAsync();
however my goal would be to get it in one fell swoop, without the need for a second call.
authentication is not a property but a relationship, so you can't specify authentication in .Select(...).
Relationships can be specified in .Expand(...) like
await _graphClient.Users[userId].Request()
.Select($"displayName,otherMails,identities")
.Expand("authentication").GetAsync();
But according to the documentation authentication doesn't support $expand and the endpoint GET /users/{user_id} supports only $select.
So it's not possible to achieve your goal by one call
We had a working application, we went through the go-live process, and everything was running live for several days. Then we started getting SSL errors, and we saw that the nuget package for the DocuSign package had an update (I believe this was all for the 11/13/2019 2019 certificates auto-update), so we updated our code, but now every request returns the USER_LACKS_MEMBERSHIP error for every token-authenticated request.
Things I can confirm are not the issue:
We have authenticated the app via account.docusign.com and the oauth signature impersonation scope, and the testing and live paths are in the API approved Redirect URIs.
We have the correct base path in the configuration (https://na3.docusign.net, as shown on our Apps and Keys page)
The base path did not change after we get the token back (The BaseUri on the Account object matches what we started with)
We are using the correct user for the configuration (The value labeled "API Username" in the Apps and Keys page is entered as "IMPERSONATED_USER_GUID" in appsettings.json and successfully used in creating the token as parameter UserID, which also matches our user account's ID shown in the backend, so we are not confusing it with TARGET_ACCOUNT_ID or CLIENT_ID, and shuffling those around causes errors much earlier at the token generation step).
We only have one user: the administrator of the DocuSign account. Their ID appears in the API configuration labeled as "API Username". The DocuSign administration backend doesn't display a membership tab anywhere for us to correct any possible issues with a user lacking membership. As far as I can tell, Membership is a higher tier account option than what we're paying for, so I'm confused how we could be having problems with a feature we haven't bought.
We get this error for checking envelope status. We get this error for trying to create new envelopes. We get this error for trying to get Account information. The only thing we can do is get an authentication token, but then that token can't be used to make any further authenticated requests.
Is there anything I'm missing that could be causing this other than some database error on DocuSign that I can't correct through the tools available to me? The package update changed the order of which class constructor accepts the ApiClient object, and there's a new AccessToken field on the Configuration class (which I filled out, but doesn't seem to have any effect, since we're still adding the Authorization/Bearer header manually). I'm out of ideas on what to try next.
Are you using the production environment or the demo environment?
I suspect that what's happening is that you are getting them mixed. As the baseUrl should not be demo.docusign.net etc. if you're using production (as indicated by your na3.docusign.net address) but you must ensure that the same account/user from production is also used.
So, the 4 things to check:
userId
accountId.
baseURI
authURI (account-d.docusign.com vs. account.docusign.com)
All of these should match and be for the same account in the same env.
I have a ASP.NET MVC (NOT ASP.NET Core) single page application with angular js on the front end.
My client (browser) talks to server through ASP.NET Web APIs. Now, the web application is on https but anonymous. There is no login/ user authentication.
The web app is in the form of a wizard where user can go back and forth and add or update input fields on the web page. The form input values are then updated on the server through Web API.
I'm looking for a way to secure my Web API calls alone, especially the POST/ PUT requests. In summary, I want to prevent any user calling my Web API directly from POSTMAN or Fiddler. The Web API, though anonymous can be only called from the browser session where the request originated.
What are options do I have to achieve this?
Can I use Anti-Forgery token here (without authentication)?
One way, I can think of achieving this is to add a custom header to each request and store some kind of session key in the header. Then, validate the custom header on every request I received from client. Are any other ways of achieving this out-of-box or some proven library without going for custom solution?
If I have to go for the above custom solution, what are the pitfalls or potential issues I need to be aware of?
First of all when you remove login and there's no authentication mechanism in your application, there's really no way to secure anything, because anyone can access your APIs. I think what you want is to make sure that your APIs are called only from your own website. Unfortunately you can't completely achieve that, since your web APIs are http/https, and anyone, from anywhere (like postman, fiddler, ...) can create a http request and call your API.
All you can do is to make it harder for your API to response to requests, like using Anti-Forgery as you mentioned.
And also I suggest you add a cookie for your application and check that cookie in every request, in this case it's more complicated ( not impossible ) to call your API using Fiddler or Postman.
And last I suggest that you use CORS, so browsers would only allow your domain to call your APIs. So nobody can call your APIs in a browser from different domain.
Based on answer from #Arvin and comment from #Evk, here's how I plan to proceed:
Once, the user starts the anonymous session generate a GUID using regular Guid.NewGuid() method and save it in DB to identify the request (I'm doing this now). However, as mentioned here,
GUID can be unique but they are not cryptographically secured.
Hence, instead of using plain-text GUID, encrypt it with current timestamp as token and append it with request query string.
For every subsequent API request, read the token from query string, decrypt it and validate it as follows:
Check the timestamp. If the time difference is more than pre-defined time (i.e. token expired), reject the request
Validate the unique id (GUID) against DB
Since, I'm not using plain text GUID anymore, the URI would not easy to guess.
Additionally, with the timestamp, URI is invalidated after sometime. While theoretically it is still possible to call the API through Fiddler but this should make it very difficult for the attacker, if not impossible.
As a further security measure, I can also add Anti-Forgery token to the request
As per my understanding this helps solving my underlying problem and with this approach, I may not even need add a cookie to secure my anonymous session.
Love to hear from you all if this approach looks good and how can it be improved.
I also once had the weird need for having session functionality on WebAPI and created an OWIN Session middleware that does exactly what you're aiming for.
The library is called OwinSessionMiddleware and is available on github and NuGet.
Usage
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseSessionMiddleware();
// other middleware registrations...
app.UseWebApi();
}
}
You can also pass some options to further tweak cookie-name, add a database backed session store (instead of in-memory), add your own session id generator (instead of default id generator which is based on GUID + secure random part generated by RNGCryptoServiceProvider).
The unique session id itself is stored as a secure cookie and the session is restored automatically by the middleware on each request.
There are extension methods you can call inside your API controller to get and set session data:
public SomeApiController : ApiController
{
public IHttpActionResult MyAction()
{
var requestCount = Request.GetSessionProperty<int>("RequestCount");
Request.SetSessionProperty("RequestCount", ++requestCount);
}
}
Create Anonymous JWT token with some claims related to your scenario, Sign it with some key, Use that as in cookie (Http Only) or As bearer token. To make it little more harder further combine it with some cookies.
1)verify token signature and
2) Verify token expiry time
3) Verify Claim(skey) against cookies(skey)- no database storage required everything is in ur JWT token.
I'm doing OAuth2 authentication in my Windows Phone 8.1 app and I'm using the WebAuthenticationBroker with the AuthenticateAndContinue() method for WP.
I'm authenticating to my server where I send two parameters and it returns my access token, without any other step in and between. Given this situation I don't have a callbakUri, so I use the WebAuthenticationBroker.GetCurrentApplicationCallbackUri()
My code looks like this:
Uri endpointURL = new Uri(_requestUrl + "&client_id=" + clientId + "&client_secret=" + clientSecret);
Uri callbackUri = WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
WebAuthenticationBroker.AuthenticateAndContinue(endpointURL, callbackUri, null, WebAuthenticationOptions.None);
I have the ContinuationManager.cs class in my project, as well as all the changed needed in the App.xaml.cs, as described here: http://msdn.microsoft.com/en-us/library/dn631755.aspx
My problem is that after I execute the code above, the Continue() method in the ContinuationManager class is never executed, so my app blocks there.
Am I missing something here?
WebAuthenticationBroker.AuthenticateAndContinue knows the authentication is done when the user is redirected to a specific page.
There's two way to deal with it:
Most services accept a parameter to set the URI the user is redirected to (the parameter is often called callback. In that case, you can generate an URI with WebAuthenticationBroker.GetCurrentApplicationCallbackUri and pass it to the WebAuthenticationBroker.AuthenticateAndContinue method (as you're doing in your code sample)
If the service doesn't accept a callback parameter, then you need to do things the other way: first check what URI the service redirects too (by calling it manually once), then pass this URI to the WebAuthenticationBroker.AuthenticateAndContinue method. For instance, let's say the OAuth service redirects to http://www.stackoverflow.com, then you need to call:
WebAuthenticationBroker.AuthenticateAndContinue(endpointURL, new Uri("http://www.stackoverflow.com"), null, WebAuthenticationOptions.None);
It looks like you are using the Client Credentials Grant. This is a non-interactive flow, and you do not need a WebAuthenticationBroker to use it. Just use an HttpClient to get the token, if you are using this flow.
That being said, this flow is probably not what you need. First of all, I am assuming that you do want to authenticate the actual user, a.k.a. the resource owner. Secondly, the flow you are using requires the client secret to be present in your phone application. That is a big no-no! This flow is intended for server-side processes!
I think you need to look at the Authorization Code Grant instead.
Was curious if there was a way to check if a user is authenticated before making a method call and then returning a custom object and not completing the call if they aren't. For example:
We set the user principal in the Application_PostAuthenticateRequest in the global.asax to the user making the request if they are authenticated or to an anonymous user if they aren't. Currently in all methods that require authentication we have something similar to the following code:
public Result GetSomeObject()
{
if (HttpContext.Current.Request.IsAuthenticated)
{
}
}
Bottom line: We want to be able to check IsAuthenticated BEFORE we let WCF get inside the method on methods that require authentication, and if true, continue, if not, return a Result object (JSON) with an authentication error.
What you need to develop is called ServiceAuthorizationManager in WCF. You can find more information about this on:
http://pieterderycke.wordpress.com/2011/04/07/implementing-restricted-access-to-a-wcf-service-with-the-serviceauthorizationmanager/
You can write a custom httpmodule to intercept the requests to the service layer and do the authentication in there.
This article may be a starting point for what you are looking for: http://pieterderycke.wordpress.com/2010/12/04/extending-wcf-creating-a-logging-component/