I am recording a visual studio web test for angularjs spa application. The application is getting data from web api application, passing oauth token for authentication. When I replay the recorded web test the oauth token is not being sent and the recorded tests are getting failed.
Please let me know how this can be fixed.
The solution was to implement a custom WebTestRequestPlugin to pass authorization token.
public override void PreRequest(object sender, PreRequestEventArgs e)
{
var token = GetOAuthToken(1500, 1);
var header = new WebTestRequestHeader("Authorization", token);
e.Request.Headers.Add(header);
}
Related
We have a legacy ASP.NET WebForms project that I am trying to modernize by using Web APIs instead of the traditional [WebMethod] statics on Code-Behind (because it is just so limited).
However, I wanted to be able to read the Session Cookie in the Web API as well. Before, I can read it in the Code-Behind by accessing the HttpContext.Current.Session["NAME_OF_COOKIE_HERE"] and then casting it to a Model - I don't know how to do this with Web APIs.
I'm using axios to talk to my Web API Controllers.
I've added the withCredentials: true to my axios config but how do I move forward from there? How exactly can you read the session cookie in Web API Controllers?
Here's a sample:
// Client for testing
axios.get(API_ENDPOINT_URL_HERE, {withCredentials: true}).then(res => res).catch(err => err);
// Web API Controller
[Route(API_ENDPOINT_URL_ACCESSIBLE_BY_THE_CLIENT_TESTING)]
[HttpGet]
public IHttpActionResult SOME_FUNCTION_NAME() {
var currentUser = // I don't know what to do from here on.
}
The answer is in this link: ASP.NET Web API session or something?
Specifically, adding the following in the Global.asax.cs
public override void Init()
{
this.PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest;
base.Init();
}
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
System.Web.HttpContext.Current.SetSessionStateBehavior(
SessionStateBehavior.Required);
}
You can read cookie just like any header property in httpRequestMessage by HttpRequestMessage.Headers .Please follow the link with proper implementation
WebAPI: Getting Headers, QueryString and Cookie Values
Also please note that if you expect a cookie in the Request then use "Cookie" header key and if you are making an rest api call and trying to find cookie in response then use "Set-Cookie"
I use an angularJS web application to login to azure => this part is working.
But when I try to access an authorized controller in my web app, I receive the "Authorization has been denied". While the authorization bearer token has been sent to the web API
my Startup.Auth.cs
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
ConfigurationManager.AppSettings["ida:Audience"]
},
});
}
ApiController
[Authorize]
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
Error:
<Error>
<script/>
<Message>Authorization has been denied for this request.</Message>
</Error>
Response Header:
VzViQXBwbGljYXRp
b245XGFwaVx2YWx1ZXM=?=
AFAIK, we would leverage adal.js and adal-angular.js in the Angular JS application to authenticate users and get tokens in the client side. Details you could follow the tutorials Azure AD AngularJS getting started and Integrating Azure AD into an AngularJS single page app to narrow this issue.
But when I try to access an authorized controller in my web app, I receive the "Authorization has been denied". While the authorization bearer token has been sent to the web API.
If you manually enable the middleware to validate the token, you need to make sure that you have correctly configured the WindowsAzureActiveDirectoryBearerAuthenticationOptions.Audience or TokenValidationParameters.AllowedAudience(s) which would be compared with the aud property from the incoming JWT token. You could press F12 when browsing your app and trace the Network or use Fiddler to capture your bearer token, then use https://jwt.io/ to decode your token.
Moreover, if you use the built-in Authentication and authorization in Azure App Service for your backend web app, you need to correctly configure the Client ID or ALLOWED TOKEN AUDIENCES for AD authentication under the Authentication / Authorization blade of your app service app.
I am working on a webapi webservice that is proteted by Azure Active Directory. The webservice cumminucates heavily with Office 365 (SharePoint / Yammer) based on the user that is signed in.
To test the web api endpoints I am writing an Console App that let me sign in with my AAD credentials and then calls the endpoints. It works, but looking for something to replace this way of testing the web api. Would be great if it’s more repeatable and that I don’t have to fill in my credentials each time. I was looking for a unit test project but can’t get the Azure AD sign in to work.
Any tips how to make this easier?
The easiest way would be to define the test runner as an application in Azure AD and have it call the API with its own client id and secret.
To do that there are a few things you would need to do:
Add appRoles to your API in its manifest in Azure AD. These are application permissions.
Define your test runner, and have it require the necessary application permissions for your API.
In your test runner you should now be able to get an access token with the client id and secret of the test runner, no user authentication required.
Some setup is needed for app permissions on the API side as well, authorization must also look at the role claims.
You can find an example for defining app permissions and also handling them here: http://www.dushyantgill.com/blog/2014/12/10/roles-based-access-control-in-cloud-applications-using-azure-ad/.
More on defining app permissions: https://stackoverflow.com/a/27852592/1658906.
More info on the application manifest in AAD: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-application-manifest.
EDIT: If you must make calls on behalf of the user in the API, then this of course won't work.
In that case, I would suggest creating a user account with the necessary access for the purpose of running the tests. It would be best not to hard-code its credentials, but store them elsewhere.
If you don't want to "fill in my credentials each time", one workaround is using the Resource Owner Password Credentials Grant flow. This flow is flexible to gain a token easily. In the Console App, you could directly use user account and password to get the access token for your protected web API . The code below is for your reference :
static void Main(string[] args)
{
test().Wait();
}
public static async Task test()
{
using (HttpClient client = new HttpClient())
{
var tokenEndpoint = #"https://login.windows.net/a703965c-e057-4bf6-bf74-1d7d82964996/oauth2/token";
var accept = "application/json";
client.DefaultRequestHeaders.Add("Accept", accept);
string postBody = #"resource=https%3A%2F%2Fgraph.microsoft.com%2F //here could be your own web api
&client_id=<client id>
&grant_type=password
&username=nanyu#xxxxxxx.onmicrosoft.com
&password=<password>
&scope=openid";
using (var response = await client.PostAsync(tokenEndpoint, new StringContent(postBody, Encoding.UTF8, "application/x-www-form-urlencoded")))
{
if (response.IsSuccessStatusCode)
{
var jsonresult = JObject.Parse(await response.Content.ReadAsStringAsync());
var token = (string)jsonresult["access_token"];
}
}
}
}
But the problem is that flow will expose the username and password directly in the code, it brings potential attack risk as well and we will always avoid handling the user credential directly. So make sure you just use this flow for testing in a secure environment. You could refer to this article for more details.
For context, I have OpenIdConnect with an ASP.NET 4 Web App working using Owin (and a lot of help from Modern Authentication with Azure Active Directory for Web Applications.
I now want to secure a separate ASP.NET 5 Web API project (to be hosted in the same AD tenant in Azure as a microservice). I started with the simple ASP.NET 5 WebApi generated in Visual Studio and added the following to the Configure in Startup.cs (at the beginning of the pipeline):
app.UseOAuthAuthentication(new OAuthOptions()
{
ClientId = "71d33a1c-505c-4815-a790-8494dd2bb430",
ClientSecret = "LajQFbf1/Nyt/6zCP5vE5YWj5VC4aNaC3i/SRtEj2sI=",
TokenEndpoint = "https://login.microsoftonline.com/7058f4f0-619f-4c16-ac31-9e209d70ff23/oauth2/token",
AuthorizationEndpoint = "https://login.microsoftonline.com/7058f4f0-619f-4c16-ac31-9e209d70ff23/oauth2/authorize",
AuthenticationScheme = "OAuth2Bearer",
CallbackPath = "/api/values"
});
This gives me an error that indicates SignInScheme must be provided, but I'm not clear on what that value should be. If I add in a string, say "OAuth2Bearer", I get further, but still get a 500 error on the request, but no exception raised in the API app, nor does the breakpoint on the first line in my API controller implementation get hit.
What am I missing? Ideally, I want to then extend the Events of OAuthOptions to add a custom claim, analogous to what I did with OpenIdConnect and the SecurityTokenValidated notification.
The OAuth2 base middleware cannot be used for token validation as it's an OAuth2 client middleware made for handling interactive flows like the authorization code flow. All the existing OAuth2 social providers (e.g Facebook or Google) inherit from this middleware.
You're actually looking for the JWT bearer middleware:
app.UseJwtBearerAuthentication(options => {
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.Authority = "[address of your OIDC server]";
options.Audience = "[audience of the access tokens issued by the OIDC server]";
});
To learn more about the different OAuth2/OIDC middleware in ASP.NET Core, don't miss this other SO post: Configure the authorization server endpoint.
I'm trying to implement a process which combines Google sign-in on client side (Web page) with server side verification and query user data (Java server).
What I did:
In Google developer console, added an OAuth 2.0 client IDs credential.
Implemented the sign-in on the web page and got the ID token after successful login.
Implemented the authentication with a backend server as explained here:
https://developers.google.com/identity/sign-in/web/backend-auth. This part also works and I can verify the authentication and get the user's e-mail address.
What I need to do now is getting the user's profile information, i.e. first and last name and access the app folder, to store relevant application data.
This is my server side code. I marked the part where I need help:
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(HTTP_TRANSPORT, JSON_FACTORY)
.setAudience(Arrays.asList(service.getClientId()))
.build();
GoogleIdToken idToken = null;
try {
idToken = verifier.verify(token); // token is the ID token received from the client
} catch (GeneralSecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (idToken != null) {
GoogleIdToken.Payload payload = idToken.getPayload();
payload.getEmail() <== This works
/*
Here I need to query Google API per the available application scopes: profile, app storage etc.
*/
}
Is it possible to use the API at this stage? If not, can I request access token here? Should I use the Client ID or do I need a different type of credential (like API key or Service account)?
ID Token represents authentication, not authorization. So you won't be able to access Google APIs just with ID Token.
In order to make requests to Google APIs from server side, do following on client side.
var auth2 = gapi.auth2.getAuthInstance();
auth2.grantOfflineAccess({
scope: 'SCOPES_COMES_HERE'
}).then(function(resp) {
// send `resp.code` to server to exchange it with
// credentials (access_token, refresh_token
});
The code is the key to exchange with access_token.
You might be inclined to implement authentication and authorization at the same time, but Google's recommendation is to separate them and request permissions as they are needed (incremental authorization). Leave the current code and add above + server side that handles code to exchange with access_token.
Detailed doc: https://developers.google.com/identity/sign-in/web/server-side-flow