Sign out different user - asp.net-core-2.0

I would like to be able to sign out some user that is logged in. By this I do not mean current user but some other user.
I, as an administrator, can deactivate or ban a user. At this point I would like to get this user and sign him out so when he makes his next request he gets redirected to log in page. After login attempt he would get a message why he cannot log in.
I am aware I can do it by writing my own authorization filter and go and fetch user from database each time but I would, if possible, like to avoid that.
Setting up authentication as follows hits mz OnValidatePrincipal each time a request is made but I do not know how to update exactly this user.
services.AddAuthentication("CookieAuthentication")
.AddCookie("CookieAuthentication", options => {
options.LoginPath = "/Login";
options.Events = new CookieAuthenticationEvents()
{
OnValidatePrincipal = new Func<CookieValidatePrincipalContext, Task>(async (a) =>
{
var expired = a.Principal.FindFirst(System.Security.Claims.ClaimTypes.Expired);
if(expired != null && bool.Parse(expired.Value))
{
a.RejectPrincipal();
return;
}
await Task.CompletedTask;
})
};
});
I am also aware that I could write my own middleware and keep some kind of list of all the users that have logged in. That list could than be easily updated by an administrator and checked by the previous event.
What I would like to know is, can I get an instance of other logged user and can I than alter its claims?

Related

Edit User's Custom Claims from Firebase

I am using firebase to generate JWT tokens to authorize access to a hasura graphql server.
I want an end user to have a callable firebase function that they can call from the app so they can change the x-hasura-role in their claims without changing other parts of their claims. I am guessing the best way to do this is to export the old custom user claims and set a new role inputted by the user.
PseudoCode:
exports.changeUserType = functions.https.onCall( async (data, context) => {
var userType = data.usertype;
// get the old user claims somehow
// check if user should be able to change their userType via a graphql query
...
// edit the user claims
return admin.auth().setCustomUserClaims(userType, {
'https://hasura.io/jwt/claims': {
'x-hasura-role': userType,
'x-hasura-default-role': 'orgdriver',
'x-hasura-allowed-roles': ['orgauditor', 'orgdriver', 'orgmanager', 'orgadmin', 'orgdirector'],
'x-hasura-user-id': user.uid // <-- from the old claims so user can't edit
}
});
If there is a better way to do this, maybe by grabbing a user's id from the auth database by checking who ran the function please tell me. Thank you in advance.
When a Firebase Authenticated user hits a Firebase Function, their uid is passed in through context. I would ensure they are authenticated first:
if (context.auth == undefined) {
throw new functions.https.HttpsError(
'failed-precondition',
'The user must be authenticated.',
);
}
Then I would grab their uid:
const uuid = context?.auth?.uid as string;
Then you can get their user using the firebase-admin library's getAuth():
// get user
const user = await getAuth().getUser(uuid);
Now finally you can set your new custom claim property:
// set the hasura role
return await getAuth().setCustomUserClaims(uuid, {
...user.customClaims,
'x-hasura-role': userType,
});
Be sure to import:
import { getAuth } from 'firebase-admin/auth';
In this way you can safely know the user is authenticated and a uid exists, then you can simply grab the user and all their existing claims, then when you go to update destructure all existing claims values, and update the one value you want.
In this way get all the user's old claims, ensure they are authenticated, retain all old claim properties, and update the one thing you want to update.
I hope that helps out!

Spotify node web api - trouble with multiple users

I am working on an app that uses Spotify Node web API and having trouble when multiple users login into my application. I am successfully able to go through authentication flow and get the tokens and user ID after a user logs in. I am using the Authorization Code to authorize user (since I would like to get refresh tokens after expiration). However, the current problem is that getUserPlaylists function described here (FYI, if the first argument is undefined, it will return the playlists of the authenticated user) returns playlists of the most recently authenticated user instead of the user currently using the app.
Example 1: if user A logins in to the application, it will get its playlists fine. If user B logins in to the application, it also sees its own playlists. BUT, if user A refreshes the page, user A sees the playlists of the user B (instead of its own, user A playlists).
Example 2: user A logs in, user B can see user A's playlists just by going to the app/myplaylists route.
My guess is, the problem is with this section of the code
spotifyApi.setAccessToken(access_token);
spotifyApi.setRefreshToken(refresh_token);
The latest user tokens override whatever user was before it and hence the previous user is losing grants to do actions such as viewing its own playlists.
Expected behavior: user A sees own playlists after user B logs in event after refreshing the page.
Actual behavior: user A sees user B's playlists after user B logged in and user A refreshes the page.
I am aware that I could use the tokens without using the Spotify Node API
and just use the tokens to make requests and it should probably be fine, however, it would be great to still be able to use the Node API and to handle multiple users.
Here is the portion of code that most likely has problems:
export const createAuthorizeURL = (
scopes = SCOPE_LIST,
state = 'spotify-auth'
) => {
const authUrl = spotifyApi.createAuthorizeURL(scopes, state);
return {
authUrl,
...arguments
};
};
export async function authorizationCodeGrant(code) {
let params = {
clientAppURL: `${APP_CLIENT_URL || DEV_HOST}/app`
};
try {
const payload = await spotifyApi.authorizationCodeGrant(code);
const { body: { expires_in, access_token, refresh_token } } = payload;
spotifyApi.setAccessToken(access_token);
spotifyApi.setRefreshToken(refresh_token);
params['accessToken'] = access_token;
params['refreshToken'] = refresh_token;
return params;
} catch (error) {
return error;
}
return params;
}
export async function getMyPlaylists(options = {}) {
try {
// if undefined, should return currently authenticated user
return await spotifyApi.getUserPlaylists(undefined, options);
} catch (error) {
return error;
}
}
Would appreciate any help on this. I am really excited about what I am making so it would mean a LOT if someone could help me find the issue...
You're on the right track. When you set your access token and refresh token, though, you're setting it for your entire application, and all users who call your server will use it. Not ideal.
Here's a working example of the Authorization Code Flow in Node: https://glitch.com/edit/#!/spotify-authorization-code
As you can see, it uses a general instance of SpotifyWebApi to handle authentication, but it instantiates a new loggedInSpotifyApi for every request to user data, so you get the data for the user who's asking for it.
If you want to use the above example, you can just start editing to "remix" and create your own copy of the project.
Happy hacking!

Facebook Messenger Bot, can someone tell me how i catch the answer of a something i asked

So i working on my Facebook Messenger Bot.
I want to know ho can i catch a answer for a question like
Bot: Enter your E-mail
User: enters e-mail
Bot: adress was added
My code looks like the sample app from Facebook
app.post('/webhook', function (req, res) {
var data = req.body;
// Make sure this is a page subscription
if (data.object == 'page') {
// Iterate over each entry
// There may be multiple if batched
data.entry.forEach(function(pageEntry) {
var pageID = pageEntry.id;
var timeOfEvent = pageEntry.time;
// Iterate over each messaging event
pageEntry.messaging.forEach(function(messagingEvent) {
if (messagingEvent.optin) {
receivedAuthentication(messagingEvent);
} else if (messagingEvent.message) {
receivedMessage(messagingEvent);
} else if (messagingEvent.delivery) {
receivedDeliveryConfirmation(messagingEvent);
} else if (messagingEvent.postback) {
receivedPostback(messagingEvent);
} else {
console.log("Webhook received unknown messagingEvent: ", messagingEvent);
}
});
});
// Assume all went well.
//
// You must send back a 200, within 20 seconds, to let us know you've
// successfully received the callback. Otherwise, the request will time out.
res.sendStatus(200);
}
});
You can set a flag for their ID that the E-Mail prompt was sent, and then after they respond check to see if it's an E-mail, and if so, then save it and echo it back to them.
If the bot is based on question/answer, what I normally do to handle response tracking is treat the bot like a finite state automata. Assign every "state" your bot can be in to some unique state identifier, and use said state identifier to determine what the user is replying to. You could also store callbacks instead of state ids, but high level this will behave the same way.
For Example:
First define a finite automata. In this case, lets assume it's:
0 --> 1 --> 2
Where 0 means new user, 1 means waiting for email response, 2 means user successfully completed registration.
User messages bot
We check our database and see it's a new user. We assume
state==0.
Because state is 0, we ignore what was sent and prompt for email
Change state to 1 to denote the email was prompted.
User replies with email.
We check database and see state==1. We use the "1" routine to do fancy stuff to verify the email and store it.
Change state to 2 to denote the email was received and the program has ended.
Note:
If the conversation id for the platform you're targeting is reset
after a certain amount of inactivity (or if you just want the bot to
mimic real conversations), store the time of each user's last
interaction and purge all inactive conversations well after the
conversation has been terminated.

Azure Active Directory Application Permission Change Delay

I am using Azure Active Directory to give my application access to the Microsoft Graph API.
When I make permission changes (e.g., read/write access for various types of data) I am noticing a delay from when the changes are saved and when I am able to access the new data through the API. I do notice, however, that after some time my API calls start to work. My questions are
Is this expected behavior?
Is there documentation somewhere that explains what permissions are needed for each Microsoft Graph API request?
Note that I am requesting a new token after making each permission change, before making the relevant API request.
When you changed your scopes (if you use Azure to manage thoses Autorizations) you have to request new consent from your users. Be sure to be able to call "one time" the ADAL AcquireTocken method, with the PromptBehavior.Always parameter.
I think it will be enough to refresh your consents and make your new scopes availables.
Here is a macro code I use :
if (mustRefreshBecauseScopesHasChanged)
{
authResult = await authContext.AcquireTokenAsync(GraphResourceId, ClientId, AppRedirectURI, PromptBehavior.Always);
}
else
{
authResult = await authContext.AcquireTokenSilentAsync(GraphResourceId, ClientId);
if (authResult.Status != AuthenticationStatus.Success && authResult.Error == "failed_to_acquire_token_silently")
authResult = await authContext.AcquireTokenAsync(GraphResourceId, ClientId, AppRedirectURI, PromptBehavior.Auto);
}
if (authResult.Status != AuthenticationStatus.Success)
{
if (authResult.Error == "authentication_canceled")
{
// The user cancelled the sign-in, no need to display a message.
}
else
{
MessageDialog dialog = new MessageDialog(string.Format("If the error continues, please contact your administrator.\n\nError: {0}\n\n Error Description:\n\n{1}", authResult.Error, authResult.ErrorDescription), "Sorry, an error occurred while signing you in.");
await dialog.ShowAsync();
}
}
For the scopes permissions détails, you will find them here :
http://graph.microsoft.io/en-us/docs/authorization/permission_scopes

Retrieve role in jhipster immediately after Auth.login

I want to send a user to a particular view after login based on a role that person has. For example, I want to send a user with ROLE_STUDENT to a student page, and a person with ROLE_TEACHER to a teacher page. Unfortunately, if I call isInRole in the controller immediately after Auth.login, that fails. Specifically, in the login function (which I moved to main.controller.js so that the login dialog appears on the main page), I have code like this:
$scope.login = function () {
Auth.login({
username: $scope.username,
password: $scope.password
}).then(function (account, $state) {
Principal.identity(true);
$scope.authenticationError = false;
$scope.account = account;
$scope.isAuthenticated = Principal.isAuthenticated;
$scope.isInRole = Principal.isInRole;
if ($scope.isInRole('ROLE_STUDENT')) {
$scope.state.go('student_dashboard');
}
}).catch(function () {
$scope.authenticationError = true;
});
};
However, the isInRole method always returns false. If I debug it, I can see in principal.service.js shows that at this point, _authenticated is false and _identity is undefined.
Now, if I comment out the isInRole conditional in the controller, so that the user always goes to the student_dashboard page, I can put isInRole code on the student_dashboard page itself, and it works great. So, it appears that something is happening between the time of the redirect, and the time the target page loads, and I want to know what that is so that I can cause it to happen and thus determine if a user has a particular role and then redirect appropriately.
I believe your problem is with
Principal.identity(true);
This actually returns a promise which does an ajax call to update the principal user, so to use the principal functions you will need to do something like this
Principal.identity(true).then(function(profile) {
$scope.authenticationError = false;
$scope.account = account;
$scope.isAuthenticated = Principal.isAuthenticated;
$scope.isInRole = Principal.isInRole;
if ($scope.isInRole('ROLE_STUDENT')) {
$scope.state.go('student_dashboard');
}
});
Otherwise the current identity is undefined.

Resources