irods-contrib / irods_auth_plugin_openid Goto Github PK
View Code? Open in Web Editor NEWLicense: Other
License: Other
Remove unnecessary output.
Transition couts that are useful to rodsLogs.
If a user authenticates via iinit and the openid login flow, and there is already a metadata entry attached to that user in iRODS, use that session id for this new client as well. This avoids the problem of having many entries auth metadata entries per user which grows theoretically infinitely depending on how many times the user logs into iRODS from scratch.
This is implemented in parallel to a change made in the heliumdatacommons services.
https://github.com/heliumdatacommons/data_registration_service/issues/7
This is needed to tell the plugin whether the session file is a sessionid or an actual access token.
Proposal: prefix value with act:
or sid:
to distinguish. If none provided, default to sid:
.
This addition could also possibly pave the way for more easily adding a JWT/JWK authentication, in which case it could use the prefix jwt:
After successful cmake,
make fails with:
/home/ubuntu/irods_auth_plugin_openid/src/libopenid.cpp:36:10: fatal error: 'gssapi.h' file not found
Please add the required dependencies to the readme, and have cmake check they are present.
libkrb5-dev
Delegate operations to this service:
https://github.com/heliumdatacommons/auth_microservice
Update server_config schema under plugin_configuration to
"authentication": {
"openid": {
"token_service": "https://<token-service-host>",
"token_service_key": "<generated-key>"
}
},
Useful for clients who wish to login with an existing access token from an identity provider identity already linked to iRODS account but which was not authenticated via the auth_microservice deployed alongside the iRODS server instance.
Still default to initiating a clean login, but if an access token is provided, switch over to this new flow.
Use verification endpoint which will be implemented in the auth_microservice.
heliumdatacommons/auth_microservice#9
Provide some mechanism through which the access token can be provided to the client library in cleartext. Possibly in place of the iinit password.
This happens when we used and configured HydroShare OAuth provider for the iRODS OAuth plugin. I have a test environment in which this problem can be reproduced. After doing iinit with openid iRODS authentication scheme successfully, ils also succeeded with empty collection. When I do an iput trying to put a file via openid iRODS authentication scheme, the following error results from iput output:
entering openid_auth_client_start
openid_auth_client_start, no _context_string
client using provider: hydroshare
entering read_sess_file
entering sess_filename()
calling getRodsEnvAuthFileName()
trying to call getenv(HOME)
HOME: /home/hongyi
leaving read_sess_file: sid=154923a3f97eed395cbbd1cb78bb04e4efcc32281c49dd6b9d
password file contains: sid=154923a3f97eed395cbbd1cb78bb04e4efcc32281c49dd6b9d
adding session_id: 154923a3f97eed395cbbd1cb78bb04e4efcc32281c49dd6b9d
client startup context
key: provider, value: hydroshare
key: session_id, value: 154923a3f97eed395cbbd1cb78bb04e4efcc32281c49dd6b9d
setting context: provider=hydroshare;session_id=154923a3f97eed395cbbd1cb78bb04e4efcc32281c49dd6b9d
leaving openid_auth_client_start
entering openid_auth_client_request
calling rcAuthPluginRequest
received comm info from server: port: [52049], nonce: [Ybf2VLXhXkz6OA9q]
attempting to read username and session token from server
entering read_from_server
read user_name:
read session token:
session token length: 0
leaving read_from_server
leaving openid_auth_client_request
entering openid_auth_client_response
**user_name: #hydroshareuserdevZone**
[-] /home/auth_microservice/irods_auth_plugin_openid/src/libopenid.cpp:988:irods::error openid_auth_client_response(irods::plugin_context &, rcComm_t *) : status [Unknown iRODS error] errno [Operation not permitted] -- message [invalid openid session, please re-run iinit]
failed with error -1 Unknown iRODS error Operation not permitted
As shown in bold above, user_name is empty after entering open_id_auth_client_response, which is the root of problem. iRODS log is not helpful since it just shows agent process existed with signal 11 segmentation fault.
in order to prevent another authorization request from being received during the 30 second window the server waits to receive one, append a nonce to the end of the authorization url that the client uses, and when the callback is received, verify that the nonce is in the request params.
I've verified that the nonce is passed through the provider and sent in the callback, just need to have the server plugin verify it. For a short-term solution, just reject any requests without the correct nonce, and tell the user to try authenticating again.
In terms of a long-term solution for this timing issue, the server should always be listening for authorization callbacks, and determine which client the access_token corresponds to based on which nonce is in that request.
For example two clients A and B attempt to authenticate around the same time, with
(A) https:///authorize?response_type=code&scope=openid%20profile%20email&client_id=1518717942&redirect_uri=http://localhost:8080/?nonce=SECRETNONCE1
(B) https:///authorize?response_type=code&scope=openid%20profile%20email&client_id=1518717942&redirect_uri=http://localhost:8080/?nonce=SECRETNONCE2
When the server sees a request from oidc provider, it can tell which client has authorized by the nonce in the request.
Add a parameter asking for a refresh token on the access token request.
When an auth request is received that references an access token that is expired, attempt to retrieve a new one with the refresh token (if it exists). If a new token is acquired, update the metadata entry for that session to contain the new one, along with the new refresh token.
If obtaining a new access token with a refresh token is not possible, delete that metadata entry, invalidating the session. This will force a re-authentication by the client user.
In additional to minimal set of openid scopes currently used to identify the user (openid,email,profile), in order to actually do anything useful with that other than identify the user, other scopes need to be able to be specified. These vary by provider. In the future we will also need to be able to talk to multiple providers, so I'm planning to do these changes all at the same time.
proposed example format for irods server_config.json file:
"plugin_configuration": {
"authentication": {
"openid": {
"globus": {
"discovery_url": "https://auth.globus.org/.well-known/openid-configuration",
"client_id": "<client-id-for-globus>",
"client_secret": "<client-secret-for-globus",
"redirect_uri": "https://<domain>/authcallback",
"scopes": ["openid","email","profile","urn:globus:auth:scope:transfer.api.globus.org:all"]
},
"google": {
"discovery_url": "https://accounts.google.com/.well-known/openid-configuration",
"client_id": "<client-id-for-google>",
"client_secret": "<client-secret-for-google>",
"redirect_uri": "https://<domain>/authcallback",
"scopes": ["openid","email","profile","https://www.googleapis.com/auth/drive.readonly"]
},
"cas": {
"discovery_url": "https://cas-server.commonsshare.org:443/cas/oidc/.well-known/openid-configuration",
"client_id": "<client-id-for-cas>",
"client_secret": "<client-secret-for-cas>",
"redirect_uri": "https://<domain>/authcallback",
"scopes": ["openid","email","profile"]
}
/// other provider configs
}
/// other auth-plugin configs
}
/// other plugin configs
}
/// other server configs
look into not using explicit thread memory management
make sure gen query memory is always cleared on error paths
previously, if iinit was run while user was already logged into irods, it would just reuse that existing session.
iinit should do a clean login flow, by providing the authorization url and waiting for a callback.
currently session/token exchange happens on a single, static port. This process is pretty fast, much less than 1 second, but if two (or more) connection login requests overlap in this period, the latter connection will fail and not be authenticated.
example test: for i in {0..10}; do (ils &); done
in the above command, around 5-8 of the 10 requests fail on my machine.
Either use a condition variable to exclude the code using that port, or maybe a more explicit queue structure. The explicit queue structure could also be useful in associating callback nonces with client requests.
Hi,
I would like to ask if this setup can be directly used from metaLnx, or one needs to do another integration (I'm trying to apply keycloak for iRODS and use it in metaLnx).
Thanks, Han
While upgrading the session token used to identify a logged-in irods session, an issue was encountered in the obf module of irods.
The base64ed sha256 hash used is 44 bytes, which is under the MAX_PASSWORD_LEN (50bytes). When this is passed to obfSavePw, the data written to .irodsA is more than 50 bytes. This should be fine because that is not the raw byte length of the password, so the 'password' value itself does not exceed MAX_PASSWORD_LEN.
However when calling obfGetPw, there is a check
(https://github.com/irods/irods/blob/master/lib/core/src/obf.cpp#L441)
which makes sure the length of the data in .irodsA is not more than MAX_PASSWORD_LEN. The data has not been 'decoded' to its original length and contents yet though, so at that stage of the process if the pw saved in obfSavePw was close to 50 bytes long, obfGetPw will always fail.
In this case a pw of length 44 (from base64(sha256)) created an irodsA of length 51. As a temporary fix I am just truncating the token down to 40 bytes, which results in an irodsA of length 47.
Right now it will wait 60 seconds. Move this up to a config option and switch over to a series of poll intervals so as not to exhaust token service threads.
Possibly disable blocking in token service, since two-hop redirects have been implemented there now, and commonsshare will not be using blocking requests.
Should be a more descriptive message to the client. Only way to know the cause now is to read rodsLog on the server.
documentation mentions to use a microservice from https://github.com/heliumdatacommons/auth_microservice; but that repo does not exist.
i found https://github.com/dsikes/auth_microservice, but not sure how it relates (or it is being developed etc etc)
Initial code was written then removed as it was not necessary at the time.
https://github.com/irods-contrib/irods_auth_plugin_openid/blob/master/src/libopenid.cpp#L1230-L1244
Previous issue:
#4
Proposed change from there, instead of reading from openid level "scopes"
array, read from:
"provider_configuration": {
"provider1": {
"scopes": [...]
}
}
If no configuration is found, default to scope openid
, as it is now.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.