Get `request.authenticated_userid` in `tween` - pyramid

Can I access request.authenticated_userid in a tween? According to https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/router.html authorization appears to happen within the territories where tweens operate.
If I add a tween to my application like:
config.add_tween("jsq.lib.middleware.my_tween.my_tween_factory")
And then I have it like:
def my_tween_factory(handler, registry):
def my_tween_callback(request):
print("Auth'd user:", request.authenticated_userid)
return handler(request)
return handler
When I do this (and have an authenticated user in session) request.authenticated_userid is None.

Related

Global variables values Node.js are missing on App Engine

I have a Node.js service deployed on App Engine which uses the Dialogflow fulfillment library. The scenario is this: I have an async function which retrieves the credentials using Secret manager and, with that info, calls an API that brings a url instance and a token back. This is a server-to-server authentication (OAuth), so it is the same for all users that access it. I set those values in global variables, like this:
let globalUser = "";
let globalPass = "";
...
async function credentials() {
const credentials = await secretsInstance.getCredentials();
const parsedCredentials = JSON.parse(credentials);
const user = parsedCredentials.user;
const pass = parsedCredentials.pass;
//setting the values to the global variables
globalUser = user;
globalPass = pass;
//call the authentication API - in the callback I set other global variables
await authApiInstance.authenticate(user, pass, callback);
}
After the callback function is called, I set the instance url and token to the global variables.
The token gets expired each 20 minutes, so I need to keep it updated. For that I call a setInterval function in which I call the authApiInstance.authenticate(...)
The problem here is that, when receiving a POST request coming from Dialogflow, I need to call another API that needs that url, which in this stage is empty for the first time, so it throws ECONNREFUSED. Then if I call the server other times, the variable is set.
The logs in GCP are like this:
2020-08-14 23:29:49.078 BRT
"Calling the loadQuestions API
2020-08-14 23:29:49.078 BRT
"The url is: /services/…
2020-08-14 23:29:49.091 BRT
"CATCH: Error: connect ECONNREFUSED 127.0.0.1:80"
2020-08-14 23:29:49.268 BRT
dialogflowGatewayProdxjmztxaet4d8Function execution took 764 ms, finished with status code:
200
2020-08-14 23:29:49.278 BRT
{ message_id: '39045207393', status: 200 }
2020-08-14 23:29:49.289 BRT
"Credentials ok"
2020-08-14 23:29:49.976 BRT
"Url set"
As it can be seen, the credentials and url were set after the API got called, so it didn't have a url to proceed successfully with the call.
I could call the function inside the POST, each time there is a request to guarantee that it will always exist, but the performance would be lost, especially dealing with Chatbots that must be quick.
I also tried the warmup approach, in which theoretically it would be called when deploying and changing the instance (but it could not be called, as by docs):
app.get('/_ah/warmup', (req, res) => {
credentials();
});
How could I approach this? I'm pretty new to Node.js and the server world.
Thanks
credentials(); by itself. no need to do it in express. The issue i would be race condition on the the shared credential.
crude example assuming the event loop has only these script in queue :
let say, you have 2 concurrent users A and B. A request and found the credential expire which in turn request new credential. B request before the credential return from A request, which in turn request another credential. Based on node eventloop, A then get credential_A , B will get credential B. If your third party only allow single credential then A will get an error from api call.
So the approach would be to forward the credential related task to one module, which manages the credential. background task or on request ( get token it expires on request) will face the same race problem. since node doesn't have context of thread, it is simple.
let credential = {}
let isUpdating = false;
const _updateCrediental = (newCrediential){
//map here
}
const _getCredential = async()=> {
try{
if(!updating){
updating = true;
const newCrediential = await apiCall();
updateCrediential(newCrediential);
updating = false;
return credential;
}else{
return false;
}
}catch(err){
throw err;
}
}
export.getCredential = ()=>{
if(credentialIsValid()){
return credential;
}
return __getCredential();
}
/// check the return if it promise type then waaait for it if its false then wait for certain time and check again.
An improvement to this would be using event to instead of using timeout.
I myself would prefer work with database as well as you might want to log credential generation as well. Most database promise certain kind of transaction or locking. (feel safer)

Sign out different user

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?

"User not found" Error when creating a child entity using ControllerB action, soon after an aspUser is created in controllerA

After the successful creation of an application user and the following line of code (in Register action in AccountController) :
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
I am trying to add a child object
var controller=DependencyResolver.Current.GetService<AnotherController>();
controller.ControllerContext = new ControllerContext(Request.RequestContext, controller);
var res = controller.Create(
new ChildEntity
{
ApplicationUserId = user.Id,
IsAcative = true
});
my create Method looks like this
public async Task<ActionResult> Create(ChildEntity entity)
{
if (ModelState.IsValid)
{
db.ChildEntity.Add(entity);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(entity);
}
My object is not created. the return valueres contains the error "user not found" propertyName : "ApplicationUserId"
Can anybody help me to understand what is going on?
ps : i have noticed that the User.Identity.GetUserId() return null !!! (may be fo some other reason, may be my problem is linked to this..)
First and foremost, the user principal is not populated until after the next page load. The sign-in process merely sets the auth cookie. That cookie needs to be sent back and the auth machinery needs to run (as part of the request pipeline), before you can get anything from User.
Second, what you're doing here is just absolutely wrong. If you want to reuse the user creation code, factor it out into another class that all your controllers can utilize. It's absolutely the wrong approach to try to new up a controller inside another action to call an action on that.

What to return for invalid user auth for OWIN method AuthenticateCoreAsync

When implementing the AuthenticationHandler<...> class, what should you return when a user authentication fails for the method AuthenticateCoreAsync?
You should return return new AuthenticationTicket(null, (AuthenticationProperties)null);
See https://github.com/IdentityModel/Thinktecture.IdentityModel/blob/master/source/Hawk/Owin/HawkAuthenticationHandler.cs#L69

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