I am building a database-backed web application with an administrator module and a user module. The administrator module allows an admin to modify properties of entities stored in the database. The user module serves dynamically generated forms based on the state of the database.
Consider the following use case:
A user requests a web page containing a form where the form options presented represent DB entities that meet a certain criteria
The requested page containing the dynamically generated form loads.
The admin makes changes in the DB to some entities loaded in the form such that they no longer meet the criteria to be displayed in the form (ie inactivated, deassociated)
The user submits the form with at least one entity selected that no longer meets the criteria to be displayed in the form.
Should the server-side validation of the submitted form pass or fail in this scenario?
The user was served a valid form but the posted form content is no longer valid with respect to the current state of the DB due to admin changes while the user was on the page...
If it should pass, should I be validating the data against the state of the database when the page loaded (leveraging the database history or using the session) or is that overkill and instead I could just validate that the posted entity is valid but does not necessarily meet the current form criteria?
its better if you dont change db properties. changing db properties will cause errors in your webapplication. try to make a form for admin in which the value of the forms is taken and displayed from the database. in this way only the values contained in the db will be modified by admin. by using this method your db properties will remain intact. And try not to give admin direct access to db.
The treatment should be similar to how a "Lost Update" problem is handled, as this IS a lost update problem. Two people pick up a row to edit at the same time, whose changes are persisted and whose changes are lost? The first guy's changes are persisted and the second guy is notified that the update failed - is the standard approach. In this case, the admin is the first guy to update - though the user might have been the first guy to read. So, the validation fails and the user is notified that the data is stale and presented with current data.
Hope this helps.
Related
As the title says, I'm developing a Custom User Storage Provider (here forth SPI) with Keycloak 15.0.2.
I’m having trouble sorting an issue where the very first access token that is issued, does not match the expected format (is missing some fields) but also seems to be issued for a different user, if I am to judge only based on the sub field of the AccessToken generated.
To ease reproduction of the issue, you can find my repository on Github here with a complete sample FE and BE along with the keycloak configuration. I also included samples of the result tokens, jwt.io links and logs on LOGS.md file on the repo.
I think I understand why this mismatch is happening, though.
Due to the fact that I start with an empty collection of users on keycloak, I need to create the users on their first login. All I have to start with is their email address which is input on the login screen.
With this information, I setup a “temporary” Federated User until I get the user data from the “real” IDP on the isValid method (where the user actually logs-in into the third party IDP) and then get his details, which are then used to fill a more complete FederatedUser profile and store it on the userLocalStorage.
It's basically this logic (it's all also explained in comments in the repo's code):
Create an adapter/model based solely on the email from the login form to be used temporarily.
Proceed with normal operation.
Then on the isValid() method:
login the user through the REST call to the backend and get the JSESSION token
on a separate call, call the Current-User REST endpoint to get user details and map them to a Dto object
create a new adapter, based on the Dto object (which already contains all the user details like name, phoneNumber, etc) and from that, add to storage as a ksession.userLocalStorage().addUser() user and enrich with custom attributes (to later be mapped into the AccessToken)
when (and if) added, clean cache with ksession.userCache().clear()
Proceed with normal operation
However, I think that the ID/model of that first temporary user is the one that is actually being used during the issuance of the first AccessToken that is generated and is being cached somehow on some other class which then generates the AccessToken with missing information/not the correct user model.
When I reload the page (forcing it to go through the login flow again), I then get the correct AccessToken with all the fields I expected the first one to have. I also noticed that the sub of the tokens are different, and this is what leads me to this conclusion.
Does this flow/conclusion seem correct to you?
And more importantly, how can I fix this?
I have no way of getting all the user data at first or a way to import it (ideally, I didn’t even wanted to Federate, just some ReadOnly data would have been enough if I could modify the AbstractUserAdapter attributes).
Can I somehow access the CredentialInput outside the isValid method?
That’s the only way I’d have to grab all the user data since the beginning.
I’d really appreciate any help you could spare. The reproduction code is just a clone/docker up away and will replicate the issue perfectly.
Please help me figure out how to make sure the token get properly set/issued the first time around
Thanks
In our Apereo CAS 5.3.8 protected application we need to display after login a screen which shows a dropdown with some values from which the user must select one option. The screen needs to be shown only if certain conditions are met, depending on some user attributes. In some scenarios all the attributes that we need are loaded after the login but in other cases we need to load additional ones depending on the user's choice. The user selection then has to be converted in some other user attributes which we want to store in the CAS assertion so that a client application can access the user attributes and make decisions based on these attributes.
In order to display this additional screen, we have created a custom multifactor provider. The loaded attributes are passed to a PrincipalFactory implementation.
Almost everything works fine except the part which happens after the user dropdown selection. The question is how can I load the principal attributes in two steps? I tried to update the principal and authentication objects in my custom action which gets triggered after the user selection but it does not work, it always keeps the old principal with the attributes loaded immediately after login.
I think the problem might be due to the fact the attributes are passed to a PrincipalFactory and probably they are only written once and become immutable. I tried to make use of a AuthenticationTransactionManager and a AuthenticationResultBuilder but was not able to add the extra computed attributes.
Any guidance would be highly appreciated.
Philosophically, I had questions about some examples on how to tackle the following REST scenarios:
1) A user who is signed in wants to 'favorite' someone's blog posting. The user id is a guid and the blog posting is a guid. Should this be a PUT because user/blog exist, or POST because there is no entry in the 'favorites' table?
2) A security row in the DB consists of 10+ properties, but I'd only want to update one part of the entity (# of failed login attempts for a user). What should the call be? Pass the entire data transfer object in JSON? Or just add a new api route for the specific action to update? I.e. a PUT with just one parameter (the # of login attempts) and pass the id of the user.
3) Similar to #2, a user class (consisting of 25+ properties) but I'd only like the user to update a specific part of the class, not the whole thing. Philosophically do I need to pass the entire user object over? Or is it OK to just update one thing. It seems I could get crazy and make lots of specific calls for specific properties, but the reality is I will probably only update 2-3 specific parts of the user (as well as obviously updating the whole thing in other cases). What's the approach here for updating specific parts of an entity in the DB?
Thanks so much
Use a POST if you don't have an ID/UUID yet.
The resource is the security record. Do a PUT on that ID, and pass a block of the properties to be changed.
Ditto (2). You should get whatever parameters will help you identify that record in the DB. If it's unsavory to send these in the POST request and you're doing AJAX, just stash them in the session.
With REST, everything is about updating discrete resources ("nouns"). It's up to you how you want to assign these, but a simple interface that uses verbs ("PUT", "GET", "DELETE", etc..) sensibly, returns relevant HTTP codes, and is easy for others to implement is the best way to go.
So, just ask yourself, "What nouns do I want to give CRUD to, and am I going to exhaust people who wish to consume my API?"
I am writing an ERM application using the Zend Framework in which user accounts are created under a main company account, enabling me to limit the number of user accounts for a company based on the license which the company paid for. Each company account has its own database (with identical structure to other companies) on my server to store data relevant to that company. The name of each companies database is stored in my "back end" database along with the rest of the companies account information and license key. The authentication system works as follows:
A new user (having never used the application before) lands on the index page and is greeted by a single text field for "Company Account Number"
After clicking "Submit", the next step in authentication is for username and password. When the user submits this form, all three pieces of information (account number, user name and password) are sent to my application's Authentication handler.
My "back end" database which stores company accounts is first queried to see if the account entered by the user exists. If it does, the company_db_name column is returned and a connection established then saved in the Zend_Registry. Otherwise, authentication has failed.
If the company account does exist, the database that was returned then has its users table queried for the specified username and password hash which either returns a successful instance of MyApp_Auth or false if the credentials were incorrect.
At first, I planned on storing user session data in the individual companies database, however I have run into the problem that there is no connection to this database when first landing on the application's index page. I have planned a workaround as follows:
Move my session storage table out of the customer's database to my "backend" database, which has a connection as soon as the application launches.
Add a "company account number" column to the table and index this column.
When a user lands on the application index page, the backend database can then be queried for the current user agent's sessionid. If it is found, then return all the necessary information i.e. the company database name to establish a connection, and the user's information to build a model with.
I have a couple questions regarding this approach:
Question 1 : Is there any risk in storing all session information for every user of my application in a single back-end database table? I am thinking in the multi-thousand user mindset.
Question 2 : I am concerned that a new user may visit the index page and by complete chance (understanding that this is a very low possibility, but still possible) have the same session_id as an existing session in the back-end database. Is this a valid concern, and if so, can it be mitigated?
Question 3 : Is there a better way, or would you recommend a different method to achieve my required functionality?
Thank you for your time!
To answer your 3 questions:
Answer 1. The is not risk as such for the storing session information of every user as long as you remove it on session expiration. The issue here is "scalability" what approach are you using? Is it scalable enough? What is the write/read speed? MySQL is 'structured' approach just like MSSQL. What processing time are you looking for? How much of information is stored? What is the architectural studies. Is it feasible enough for your client?
Answer 2. Ideally the session_id will not be the same so that should not be your concern.
Answer 3. You need NoSQL (Not Only SQL but, even more) approach. Read this
Looking at the MASSIVE-ness of your data, I strongly suggest you to go for HBASE (uses Hadoop, easy for multi cluster) or CouchDB or if you are Amazon fan dynamoDB.
Questions? :)
EDIT: Just realized you are using Zend Framework. In that case, you can also use MongoDB, and use Shanty Mongo library.
I have problem to find the best way how isolate users data stored in db.
Now if i login and access to my profile i can see data loaded from db.
example .../myprofile/PeterM
but if i manualy change address to .../myprofile/MartaM i see data stored in db for user marta
how can i isolate members data.
Thanks for my maybe stupid question.
You should always check that the user who is accessing the data is allowed to do so. Don't rely on just the querystring.
So for instance, instead of performing your database lookup based on the username in the querystring, get the information based off the currently authenticated user.
If I'm logged in as Brandon, then GetUser(HttpContext.Current.User.Identity.Name); should always return my information, regardless of whose name is passed in to the controller action.
Or just check that the username you're retrieving is the same as HttpContext.Current.User.Identity.Name