MS Teams permissions for creating a group - azure-active-directory

Can someone help me understand how to add a permission to a MS-Graph API call?
I'm trying to create a new team/group but I'm getting a permission error. Obviously I need add the Team.Create permission if I want to create a Team. Which I did as seen in the image below
Here's the sample code where I tried to add the permission to the MSAL client request:
// Initialize Graph client
const client = graph.Client.init({
// Implement an auth provider that gets a token
// from the app's MSAL instance
authProvider: async (done) => {
try {
// Get the user's account
const account = await msalClient
.getTokenCache()
.getAccountByHomeId(userId);
let scope = process.env.OAUTH_SCOPES.split(',');
scope.push("Team.Create");
console.log("Added a extra permission request");
console.log("scope = " + scope);
if (account) {
// Attempt to get the token silently
// This method uses the token cache and
// refreshes expired tokens as needed
const response = await msalClient.acquireTokenSilent({
scopes: scope,
redirectUri: process.env.OAUTH_REDIRECT_URI,
account: account
});
console.log("\nResponse scope = " + JSON.stringify(response) + "\n");
// First param to callback is the error,
// Set to null in success case
done(null, response.accessToken);
}
} catch (err) {
console.log(JSON.stringify(err, Object.getOwnPropertyNames(err)));
done(err, null);
}
}
});
return client;
Then I get the following error:
The user or administrator has not consented to use the application with ID 'xxxxxxx'
named 'Node.js Graph Tutorial'. Send an interactive authorization request for this user and resource
I did give permissions to Team.Create in the Azure Active Directory, so how do I consent to this app gaining access? Note this code is the tutorial for learning Graph: https://learn.microsoft.com/en-us/graph/tutorials/node

Judging by the screenshot, you can't give admin consent to the permission as it is grayed out.
You'll need to try if you can grant user consent.
acquireTokenSilent won't work in this case since consent is needed.
You need to use one of the interactive authentication methods to trigger user authentication, at which time you can consent to the permission on your user's behalf.
In that sample specifically, you probably need to modify the scopes here: https://github.com/microsoftgraph/msgraph-training-nodeexpressapp/blob/08cc363e577b41dde4f6a72ad465439af20f4c3a/demo/graph-tutorial/routes/auth.js#L11.
And then trigger the /signin route in your browser.

Related

Firebase function linkAndRetrieveDataWithCredential doesn't work

To link an anonymous user to a newly-created user via email&pass I use the following function linkAndRetrieveDataWithCredential
For some reason I get the following error:
__WEBPACK_IMPORTED_MODULE_12_firebase_app___default.a.auth(...).currentUser.linkAndRetrieveDataWithCredential is not a function
The function is documented in the official Firebase documentation on how to link an anonymous user.
https://firebase.google.com/docs/auth/web/anonymous-auth
background: I use React.js and hence install Firebase via NPM.
What am I doing wrong ?
My code:
//if the user is anonymous, then upgrade the anonymous user to be the email&pass user.
//get the Credential object
var credential = firebase.auth.EmailAuthProvider.credential(this.state.email, this.state.password);
//get the Credential object
firebase.auth().currentUser.linkAndRetrieveDataWithCredential(credential).then(function(usercred) {
var user = usercred.user;
console.log("Anonymous account successfully upgraded", user);
//the user was created. redirect to Home page
window.location.assign("/");
Apparently the function was deprecated.
the right solution is documented here:
Firebase Convert Anonymous User Account to Permanent Account Error
// (Anonymous user is signed in at that point.)
// 1. Create the email and password credential, to upgrade the
// anonymous user.
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
// 2. Links the credential to the currently signed in user
// (the anonymous user).
firebase.auth().currentUser.linkWithCredential(credential).then(function(user) {
console.log("Anonymous account successfully upgraded", user);
}, function(error) {
console.log("Error upgrading anonymous account", error);
});

Why is Identity Server4 Logout not working? (without MS Identity)

I am trying to implement my own OAuth Server with IdentityServer4, and so far everything works except the logout.
I am not using Microsoft Identity, as I already have an existing WebApp with a WebApi which is handling the user-related CRUD operations. Thus I am using an existing Database for fetching Users and validating their username and PW. If validation is successful, my validation Method returns an object of type "AuthenticatedUser" (which is a UtilityClass I made).
Edit My Client is a Xamarin App, and using IdentityModel.OidcClient2 for login. I am testing with the UWP platform, Edit which uses WebAuthenticationBroker for Login/Logout calls.
Code I use is the one from the QuickStart UI Example, with a small modification to validate the users from my existing DB:
Edit Now I am explicitly creating Claims, ClaimsIdentity, and added CookieAuthenticationDefaults.AuthenticationScheme wherever possible.
//my method for user validation
AuthenticatedUser user = await _userService.ValidateCredentials(model.Username, model.Password);
//rest of login code from quickstart ui
if (user != null)
{
await _events.RaiseAsync(new UserLoginSuccessEvent(user.FirstName, user.Id.ToString(), user.FirstName));
// only set explicit expiration here if user chooses "remember me".
// otherwise we rely upon expiration configured in cookie middleware.
AuthenticationProperties props = null;
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
};
//things we know about the user that we wish to store on the cookie
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Role, user.RoleId.ToString()),
new Claim(JwtClaimTypes.Name, user.FirstName + " " + user.LastName),
new Claim(JwtClaimTypes.Subject, user.Id.ToString())
};
var userIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
//set the cookie using the SignInAsync method
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, props);
// issue authentication cookie with subject ID and username
await HttpContext.SignInAsync(user.Id.ToString(), user.FirstName, props);
//....
So far, this seems to work well. When the Login fails, I cannot access my protected Api, if the login succeeds, I get an AccessToken with the claims I requested, and I can access the protected Api methods as expected.
When I call the logout endpoint (done by a HTTP request to the endpoint, providing id_token_hint as query parameter), though, for some reason the User is not Authenticated - therefore my User is never Logged out by calling HttpContext.SignOutAsync().
if (User?.Identity.IsAuthenticated == true) //always evaluates to false?! why?
{
// delete local authentication cookie
await HttpContext.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
Edit After using WebAuthenticationBroker instead of a simple HTTP Request for calling the logout endpoint, the console Logs though state that "XamarinApp" got logged out. Even though HttpContext.SignOutAsync() was never called What does this mean? I doubt that this is Ok, but the app behaves as I want afterwards, e.g I can log in with a new user.
[16:43:12 Debug] IdentityServer4.Hosting.EndpointRouter
Request path /connect/endsession matched to endpoint type Endsession
[16:43:12 Debug] IdentityServer4.Hosting.EndpointRouter
Endpoint enabled: Endsession, successfully created handler: IdentityServer4.Endpoints.EndSessionEndpoint
[16:43:12 Information] IdentityServer4.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.EndSessionEndpoint for /connect/endsession
[16:43:12 Debug] IdentityServer4.Endpoints.EndSessionEndpoint
Processing signout request for anonymous
[16:43:12 Debug] IdentityServer4.Validation.EndSessionRequestValidator
Start end session request validation
[16:43:12 Debug] IdentityServer4.Validation.TokenValidator
Start identity token validation
[16:43:12 Debug] IdentityServer4.EntityFramework.Stores.ClientStore
xamarinApp found in database: True
[16:43:12 Debug] IdentityServer4.Validation.TokenValidator
Client found: xamarinApp / Xamarin App
[16:43:12 Debug] IdentityServer4.Validation.TokenValidator
Calling into custom token validator: IdentityServer4.Validation.DefaultCustomTokenValidator
[16:43:12 Debug] IdentityServer4.Validation.TokenValidator
Token validation success
{
//Token details omitted here for the sake of simplicity.
}
}
[16:43:12 Information] IdentityServer4.Validation.EndSessionRequestValidator
End session request validation success
{
"ClientId": "xamarinApp",
"ClientName": "Xamarin App",
"SubjectId": "unknown",
"PostLogOutUri": "xamarinformsclients://callback",
"Raw": {
"id_token_hint": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA3RjlGQ0VFRTVCMzM4ODkzODZCNjc2MTZCRjZCOTFEMUEwRkRBQjAiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJCX244N3VXek9JazRhMmRoYV9hNUhSb1AyckEifQ.eyJuYmYiOjE1Mjg5MDA5ODYsImV4cCI6MTUyODkwMTI4NiwiaXNzIjoiaHR0cHM6Ly9sYXB0b3AtMW0waW4zMW46NDQzODciLCJhdWQiOiJ4YW1hcmluQXBwIiwibm9uY2UiOiI4YjZjZWRkMDFhMjQ0ZDJmOWY3ZGM4NzZmM2NmZGYwNiIsImlhdCI6MTUyODkwMDk4NiwiYXRfaGFzaCI6IkZualBtd2hiZTNmOVRITjEzM0NSZWciLCJzaWQiOiJkMmJlZTgyYzg0YWY2NGI5ZDUyYmZlNmExNmU1MTNmZiIsInN1YiI6IjI4IiwiYXV0aF90aW1lIjoxNTI4OTAwOTgzLCJpZHAiOiJsb2NhbCIsInVzZXJfaWQiOiIyOCIsInJvbGVfaWQiOiI0IiwibmFtZSI6IlRpbGwgU2F1YmVybWFubiIsImZhbWlseV9uYW1lIjoiU2F1YmVybWFubiIsImFtciI6WyJwd2QiXX0.ZjwL8nuq-WD3D-pXruZtE_I5TyNNO_ZMabz2JiKVnTaTnITwGV5CIJcLcWSpBCOyaSFXKUicAtROeWLReuk_LWoUTKXcX7lyv5VP9-ItBNA13EwgsbhQX7BgS2lbE9fQU7OgGARJcpvPKaT9FabFtEZsNYW9sNeBo-6CUPkYtVH_rjRyLihFi2NlZlkHBc7_oPE0hsjf61QIwyGZEhVXvDXkP_Q9t_Bfr3_QrUF6MfyhzLs0KcMwbtlWUxYw51J8phz7RPUXbbiZ1tG9Ay4DNy8RZbzfI-uFAbrqH7waLo_f5JO15eYc-xICl22ZS_4lW0_MlzP_rq46PnGOwNBqlg",
"post_logout_redirect_uri": "xamarinformsclients://callback"
}
}
Edit As far as I can understand, this probably has to do with my Xamarin Client and Cookies. I found tutorials on how to configure a MVC Client, IDSVR4 and the Cookie Middleware, but nothing regarding native Apps, IDSVR4 and Cookie Middleware.
How is IDSVR4 (or the logout in particular) supposed to work with a non-MVC Client and IdentityModel.OidcClient?
Finally I found the reason. In the QuickstartUI Examples, the Class "AccountConteroller.cs" sets Explicit Expiration only if the user chooses the "remember me" Option. I removed the if condition, and finally the authentication cookie is properly stored, on logout my user is not null anymore, and everything is fine.
class AccountController
...
AuthenticationProperties props = null;
//ALWAYS SET EXPLICIT EXPIRATION, SO COOKIE CAN BE DELETED WHEN LOGGING OUT
//if (AccountOptions.AllowRememberLogin && model.RememberLogin)
//{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
// };

IBM Watson tokens expire in one hour. Code to refresh the tokens?

I'm setting up IBM Watson Speech-to-Text. This requires an access token, documented here:
"Tokens have a time to live (TTL) of one hour, after which you can no longer use them to establish a connection with the service. Existing connections already established with the token are unaffected by the timeout. An attempt to pass an expired or invalid token elicits an HTTP 401 Unauthorized status code from DataPower. Your application code needs to be prepared to refresh the token in response to this return code."
I don't see on the documentation page an example of application code to refresh the token.
Should my code generate a new token for every user who downloads the JavaScript app? Or should the server request a new token every hour, and give all users the same token for an hour?
The shell command to get a token is:
curl -X GET --user username:password \
--output token \
"https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api"
That looks like I can send an HTTP request from my JavaScript app and get back a token. Should I request the token as a file, and then have my app get the token from the file?
enter code hereWhat worked was to use Cloud Functions for Firebase (part of Google Cloud Functions), triggered on a user logging in, running Node to send an HTTP request to get the token and then write the result to an AngularJS value service.
This Cloud Function works:
// Node modules
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const request = require('request'); // node module to send HTTP requests
const fs = require('fs');
admin.initializeApp(functions.config().firebase);
exports.getWatsonToken = functions.database.ref('userLoginEvent').onUpdate(event => { // authentication trigger when user logs in
var username = 'groucho',
password = 'swordfish',
url = 'https://' + username + ':' + password + '#stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/speech-to-text/api';
request({url: url}, function (error, response, body) {
var tokenService = "app.value('watsonToken','" + body + "');";
fs.writeFile('../public/javascript/services/watsonTokenValue.js', tokenService, (err) => {
if (err) throw err;
console.log('The file has been saved!');
}); // close fs.writeFile
}); // close request
}); // close getWatsonToken
In the controller:
firebase.auth().onAuthStateChanged(function(user) { // this runs on login
if (user) { // user is signed in
console.log("User signed in!");
$scope.authData = user;
firebase.database().ref('userLoginEvent').update({'user': user.uid}); // update Firebase database to trigger Cloud Function to get a new IBM Watson token
} // end if user is signed in
else { // User is signed out
console.log("User signed out.");
}
}); // end onAuthStateChanged
Walking through the Cloud Function, it injects four Node modules, including request for sending HTTP requests, and fs for writing the results to a file. Then the trigger is set for an update to a location userLoginEvent in the Firebase database (which I created from the console). Next, the HTTP request goes out. The response (the token) is called body. app.value('watsonToken','" + body + "');" is an Angular value service to wrap the token. Then fs writes all this to a location in my project.
In the AngularJS controller, onAuthStateChanged triggers when a user logins in. The user.uid is then updated to the location userLoginEvent in the Firebase database, and the Cloud Function triggers, the HTTP request goes out, and the response is written to an Angular service.

How do I renew the timeout of my ApplicationCookie in Identity 2.0

Is there a way to renew the authentication timeout of a cookie as part of a particular web request? I have an Angular app on top of my MVC 5 project and I need it to keep my server session alive in between requests. I've got the Angular part working, but it appears that hitting a URL on my server is not sufficient to reset the Auth timeout. I am new to Identity so I am probably missing something simple?
My Startup.Auth.cs code:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
ExpireTimeSpan = TimeSpan.FromSeconds(30),
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(20),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
}
And my simple method (authorization is set up globally for all requests that do not have [AllowAnonymous]):
[HttpGet]
public HttpResponseMessage KeepAuthAlive()
{
// Renew Auth Cookie - how?
}
Re-SignIn the User (this code assumes you have UserManager and SignInManager available as per the default Account controller and an async ActionResult). I haven't tested this, but it should hopefully work:
ApplicationUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user != null)
{
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
}

Unauthenticated call to Endpoint working for an API method with authentication

I am facing issue with Endpoints authentication.
This is the api code I am using
#ApiMethod(name = "myapiname.myapimethod", scopes = { Constants.EMAIL_SCOPE }, clientIds = {
Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID,
Constants.API_EXPLORER_CLIENT_ID }, audiences = { Constants.ANDROID_AUDIENCE })
public Result myapimethod(User user) throws OAuthRequestException, IOException {
// some work
return new Result();
}
In API explorer, it shows that the method requires Authorization, but it is getting successfully executed even without authorizing the request in API explorer.
Any help will be highly appreciated.
Thanks in advance.
Adding an User parameter alone won't check if the endpoint request is authenticated, we need to check that ourselves refer the documentation https://developers.google.com/appengine/docs/java/endpoints/auth#Java_Adding_a_user_parameter_to_methods_for_auth
`If an incoming client request has no authorization token or an invalid one, user is null. In your code, you need to check whether user is null and do ONE of the following, depending on the condition:
If the user is present, perform the authorized action.
If the user is null, throw an OAuthRequestException.
Alternatively, if the user is null, perform some action for an unauthorized client access if some sort of unauthorized access is desired.`

Resources