Sub account access keys and storage staking - smartcontracts

Lets say a contract that lives on account factory.near has a create method that creates sub accounts and deploy contracts to it like the following..
const promise = ContractPromiseBatch.create(subaccount)
.create_account()
.deploy_contract(Uint8Array.wrap(changetype<ArrayBuffer>(CODE)))
.add_full_access_key(base58.decode(Context.senderPublicKey))
.function_call(
"init",
new PlaceInitArgs(Context.sender),
Context.attachedDeposit,
XCC_GAS
)
Does the parent account that holds the factory contract automatically have full access or function call access to the sub account?
Would all sub accounts have the same contract hash since the same WASM file is being deployed onto it?
What would happen if the attached deposit isn't enough to stake storage? Would the account be made without the contract deployed or would both fail?
If a subaccount is deleted, would the NEAR tokens staked as storage also be returned to the specified beneficiary in the delete function call?

Does the parent account that holds the factory contract automatically have full access or function call access to the sub account?
No the access control doesn't work between accounts. It is invalid to say that some account has full access to some other accounts. You have full access to some account if and only if you own a full access key (the private key) of that account.
Would all sub accounts have the same contract hash since the same WASM file is being deployed onto it?
Yes if they are created this way.
What would happen if the attached deposit isn't enough to stake storage? Would the account be made without the contract deployed or would both fail?
The actions are batched in one receipt. The execution of a receipt is atomic -- it either succeeds or the entire state touched in between is rolled back. In this case, the account creation will fail if attached deposit is not enough.
If a subaccount is deleted, would the NEAR tokens staked as storage also be returned to the specified beneficiary in the delete function call?
Yes

Related

NextAuth - OAuthAccountNotLinked - Imported data from another website - Autolinking

I have OneLogin setup in my application and is working fine. Am using MongoDB database for storing the sessions, accounts and users.
And now, I imported user data from my old WordPress website(which doesn't uses OneLogin, but the native WordPress login).
So basically I imported the user data from WordPress and populated the users collection using the email_id, name, etc. When I login with the OneLogin into my application, it throws the error saying OAuthAccountNotLinked. When researched I can see that you are not recommending the auto-linking of user accounts for safety reasons. But in my case, it's a OneLogin provider that my client's organization that has now started using. And new OneLogin user registrations are manually approved by the admin. So security wise it won't be a problem. We are only using OneLogin as auth provider!
How can I setup auto-linking in this scenario? Because I have 10,000s of Users in my MongoDB collection(imported from old WordPress website). And each User is being requested to manually register at OneLogin using the same email id they were using before in the old WordPress website and is manually approved within the OneLogin.
Thanks
Quote right from the original site
Automatic account linking on sign in is not secure between arbitrary providers - with the exception of allowing users to sign in via an email addresses as a fallback (as they must verify their email address as part of the flow).
When an email address is associated with an OAuth account it does not necessarily mean that it has been verified as belonging to account holder — how email address verification is handled is not part of the OAuth specification and varies between providers (e.g. some do not verify first, some do verify first, others return metadata indicating the verification status).
With automatic account linking on sign in, this can be exploited by bad actors to hijack accounts by creating an OAuth account associated with the email address of another user.
For this reason it is not secure to automatically link accounts between arbitrary providers on sign in, which is why this feature is generally not provided by authentication service and is not provided by NextAuth.js.
Automatic account linking is seen on some sites, sometimes insecurely. It can be technically possible to do automatic account linking securely if you trust all the providers involved to ensure they have securely verified the email address associated with the account, but requires placing trust (and transferring the risk) to those providers to handle the process securely.
Examples of scenarios where this is secure include with an OAuth provider you control (e.g. that only authorizes users internal to your organization) or with a provider you explicitly trust to have verified the users email address.
Automatic account linking is not a planned feature of NextAuth.js, however there is scope to improve the user experience of account linking and of handling this flow, in a secure way. Typically this involves providing a fallback option to sign in via email, which is already possible (and recommended), but the current implementation of this flow could be improved on.
Providing support for secure account linking and unlinking of additional providers - which can only be done if a user is already signed in already - was originally a feature in v1.x but has not been present since v2.0, is planned to return in a future release.
You probably need to write your own implementation to handle such a situation. And call that implementation on each provider call back. Like a check, the email already exists in DB, through an extra level of verification like OTP etc. Finally, when everything passes, let the user in and store some extra info in the DB for future reference.
Since I wasn't able to find a straight forward solution, I come up with a workaround. It's not a perfect solution, but does the job. Maybe someone else will post a better solution here.
So what I did is, I have all the old user data imported to the users collection in my MongoDB database. And NextAuth uses this users, accounts and session collections to store the User and related data. Btw am storing the session data in database.
In my case, we have sent unique OneLogin registration URLs(created from the OneLogin Admin Dashboard) to our existing users for them to create a new account in OneLogin. Then when the User registers an account at OneLogin, the admin approves/rejects the User. If they are approved, they will be eligible to login to our app using their OneLogin credentials.
What I noticed is that, when a User tries to login, NextAuth checks the email field in users collection to find a matching record. Since we imported the Users from WordPress database, we only have records in users collection and nothing on the accounts collection. In accounts collection, NextAuth is storing the access_token, user_id (mapping to users collection), provider details, etc.
So during login, the NextAuth does the internal checks and finds the existing email in the users collection, but it fails to identify the user as there's no info about the provider(OneLogin) details.
Record from accounts collection:
So what I did is, updated all records in users collection by appending a _TEMP to the email field's values. For example, if there's a record with the value abc#abc.com, it will become abc#abc.com_TEMP
Then what I did is, I wrote an API route(/api/check_old_account) in my NextJS application, where it does the following:
gets the currently logged in User's email id (from NextAuth session)
searches the users collection for the same email id with a "_TEMP" at the end
if there exists a _TEMP version of the currently logged in User, then return a response saying an old account exists
Then in the HOME page, I wrote the code to call the above mentioned api (/api/check_old_account) if the User is logged in. This call is made only once in the HOME page, when everything is loaded. Here the login using OneLogin works without errors because we renamed the existing email id in users collection by appending _TEMP. So when User logins, the users collection inserts a new record with their email and related data to the accounts collection also. Basically there would be two records in users collection for that User now. One is their original email id record that got inserted now when the logged in (eg: abc#abc.com) and their old imported account (eg: abc#abc.com_TEMP). The reason why I wrote the code to call the API in the HOME page only is because, after User logs in, they will be redirected to the HOME page. So thought it won't be necessary to write the code globally or somewhere else.
So, if the above API response says that there's an old account that exists, I display a warning popup to the User saying that there's an old account existing in the database and asks whether they want to link that old account. If the User presses YES button, I make an API call to /api/link_old_account. In this API route, the code is written to perform this:
if there's a _TEMP version email of the currently logged in user in users collection, find the respective record _id that has mappings in the accounts collection.
then change the value of the userId field of that respective record(currently logged in user id) in accounts collection, with the user id of the record with the _TEMP version email.
then delete the record with the _id of the currently logged in user
then update the email field by removing the _TEMP from it
then deletes the records that matches the currently logged in user in the userId field of sessions collection. So that the currently logged in sessions of this User would be invalidated.
then redirects the user back to the HOME page using res.redirect(307, '/')
The solution seems to be working fine so far.

Is there a way to authenticate a user's wax/EOS wallet on the server side without making any blockchain transactions?

I'm trying to authenticate a user's wax wallet identity on the server. The method I'm trying to follow is this -
The client sends the server the (claimed) WAX wallet address
The server creates a random hash and sends it to the client
The client creates a transaction with the hash and signs it. Instead of pushing it to the chain, the transaction is created with broadcast set to false and it sends the signed transaction to the server
This is the part where I'm having a problem. What I want to do is use the eosjs API to get the actual public key of the wallet address, and then use eosjs-ecc's recover or verify methods to get a public key from the transaction and verify that it is the same. When I try this, it is producing different public keys each time and none of them match the actual one.
Here's the code I have at the moment: https://github.com/udbhav-s/waxlogindemo
If the method I'm trying isn't possible, is there any other way to authenticate a user without using on chain transactions?

When connecting to an API do I need an access token per each user using my application?

I'm connected to an API that provides information about cars based on their registration. According to the docs the api can provide both user specific data and general data about the registration supplied.
I am using the connection method which does require specific users data, and therefore does not require me to gain access to any specific users account.
On my end users will visit my application and enter a registration number which I will use to call the API and return all of the information about the car.
Am I right in my thinking that my application is essentially the 'user' as far as the api is concerned, and I will only need to use one access token. I can then use this access token to make multiple API calls (one for each user that searches on my application)?
Or will i need to set up an access token for each user that visits my application and treat them separately.
Only your application making the API requests requires a token, unless the licence agreement/documentation of this car API says otherwise.
As far as your users are concerned, your application is just magically sourcing the registration info from its database.

Can client and employee be in the same pool?

Suppose a client wants to be able to create a trusted profile (sort of like a digital signature). The client creates their account, fills out the application and then confirms it so an employee can verify their identity and create the trusted profile.
Is it alright for both the client and employee to be in the same pool, or should they be in distinct pools such that only messages can pass between the two?
Distinct pools. There are several aspects supporting this:
The client typically does not belong to the same organisation/system, thus it should be modelled as a separate pool.
The application form is a document that is handed over from the client to the point of confirmation. The semantics of handing over a document or form is equivalent to passing a message to another party. Message passing makes it very explicit, which data is being passed. When using sequence flow, it is less clear (although you could attach a data object to the flow).
Besides of those points, I stumbled upon the first "Logging" task, which seems to be modelled from a very technical perspective. I'd rather model an activity "Check if client account exists", then have a gateway that decides whether an account needs to be created or not and then proceed. The case that the account is not existent is IMO a very valid case from a business perspective and not to be considered an exception/error.

Revoke Shared Access Signatures after initial access in Azure Storage

I would like to essentially allow for one-time access to certain blob resources, requiring the user to check back with my server to get a new shared access signature before being able to access the resource again.
I have an implementation of this that I currently use, but I'm curious if there's something more ideal out there (particularly something already implemented in the Azure API that I missed).
Right now, a user can request the resource from the server. It validates their access to it, creates a unique hash in a database, directs the user to a link with that hash and the user loads the page. Once the page loads and they've completely downloaded the resource, I immediately invalidate the hash value in the database so it cannot be used again.
I know that Shared Access Signatures allow for time-based expiration, but do they allow for any sort of retrieval-count-based expiration, in that the user can completely download the resource and then the SAS invalidate itself? Thanks!
One time use is not supported by SAS tokens. If you get a chance it would be great if you could add this request to our Azure Storage User Voice Backlog. I would also encourage other people with the same requirement to vote on that as wel.
Thanks
Jason