How to activate OneLogin Protect push challenge with SAML assertions - api

I have figured out that to use OneLogin Protect with saml assertions, you need to call the SAML verify factor without the OTP provided, and read about a similar question here, but if I simply put this in a loop with a sleep, the User is bombarded with OTP calls, until they hit "Accept". If the user takes 10-20 seconds to pull their phone out, and I sleep for 20 seconds, that means that users who have their phone immediatly available and could response in 2-3 seconds, have to wait 20 seconds to cover the slower calls.
To adress this, I would like to check the saml assertion verify without sending a push notification, and just the state_token.
I have also noticed that if I were not to use SAML assertions, I could do this as described here: https://developers.onelogin.com/api-docs/1/multi-factor-authentication/overview but that requires me to give either Manage users or Manage All permissions to the API keys. As this is a Python cli utility to handle aws saml auth, and one way or another, we need to distribute those API keys to users, this seems like excessive privileges for a user to log into AWS.
Does anyone know how can I check the status of an OTP for OneLogin Protect with SAMl assertions, without creating a new OTP call every time I check the status?
Example code
ol_client = OneLoginClient(
'client_id',
'client_secret',
'us',
)
saml_resp = ol_client.get_saml_assertion(
'ol_username',
'ol_password',
'aws_app_id',
'subdomain'
)
call_result =ol_client.get_saml_assertion_verifying(
'onelogin_aws_app_id',
device.id,
saml_resp.mfa.state_token
)
if call_result is None:
verify_result = None
while verify_result is None:
sleep(1)
verify_result =ol_client.get_saml_assertion_verifying(
'aws_app_id',
device.id,
saml_resp.mfa.state_token
)

I've found an answer by now. Just forgot to update:
The API exposes a Message field in the verifyFactor endpoint. While it's pending for the user to act on it, it will contain the string pending.
rMfa, err = c.VerifyFactor(token, &pMfa)
for strings.Contains(rMfa.Message, "pending") && timeout > 0 {
time.Sleep(time.Duration(MFAInterval) * time.Second)
rMfa, err = c.VerifyFactor(token, &pMfa)
if err != nil {
s.Stop()
return nil, err
}
timeout -= MFAInterval
}
I resorted to check every second until the timeout expired. The full implementation can be seen here: https://github.com/allcloud-io/clisso/blob/master/onelogin/get.go#L133

Related

API of Polarion ALM occasionally does not authorize any request

I have wrote some Python code that logs in and reads some data from Polarion ALM server via API (more informarion about Polarion API: https://almdemo.polarion.com/polarion/sdk/index.html). In my code I have used zeep Python package to handle SOAP.
My algorithm is simple:
1) Log in via logIn web service (https://almdemo.polarion.com/polarion/sdk/doc/javadoc/com/polarion/alm/ws/client/session/SessionWebService.html#logIn-java.lang.String-java.lang.String-)
2) Add current session to header - so the current session remain alive.
3) Try to read some data, for example via getRootProjectGroup web service (https://almdemo.polarion.com/polarion/sdk/doc/javadoc/com/polarion/alm/ws/client/projects/ProjectWebService.html#getRootProjectGroup--).
4) Regardless of what is happening I close the current session via endSession web service (https://almdemo.polarion.com/polarion/sdk/doc/javadoc/com/polarion/alm/ws/client/session/SessionWebService.html#endSession--).
What I observed:
Ocassionally, at point 3 I receive response with Authorization Error (snippet with response):
<soapenv:Fault>\n <faultcode>soapenv:Server.generalException</faultcode>\n <faultstring>Not authorized.</faultstring>\n <detail>\n <ns1:stackTrace xmlns:ns1="http://xml.apache.org/axis/">Not authorized.\n\tat com.polarion.alm.ws.providers.DoAsUserWrapper.invoke(DoAsUserWrapper.java:37)\n\tat org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)\n\t..
or everything is good and I receive:
{
'groupURIs': {
'SubterraURI': [
'subterra:data-service:objects:/default/${ProjectGroup}Group'
]
},
'location': None,
'name': 'ROOT_CTX_NAME',
'parentURI': None,
'projectIDs': None,
'uri': 'subterra:data-service:objects:${ProjectGroup}Group',
'unresolvable': False
}
What surprises me the most:
- I always uses the same credential (username and password)
- the session ID of the in request (point 3) is the same as in the server response during log in (point 1) so the session shall remain alive
- if I put my code in the loop (for example 1000 executions), the result for all attempts is always the same (1000 successes or 1000 failures), even if I add a wait (e.g. 1s) between the attemps
I would like to know why server rejects some of the requests. Is it some kind of Polarion server issue? How could I make a work around to somehow connect with the server and be able to read some data from the server even if it reject my first request.
It appears that it is issue with SOAP client (and relatively popular one). To fix it, I have turned off TLS verification. More details in:
https://python-zeep.readthedocs.io/en/master/transport.html

intermittent error from rally 'Not authorized to perform action: Invalid key' for POST request in chrome extension

I developed a chrome extension using Rally's WSAPI v2.0, and it basically does the following things:
get user and project, and store them
get current iteration everytime
send a post request to create a workitem
For the THIRD step, I sometimes get error ["Not authorized to perform action: Invalid key"] since end of last month.
[updated]Error can be reproduced everytime if I log in Rally website via SSO before using the extension to send requests via apikey.
What's the best practice to send subsequent requests via apikey in my extension since I can't control end users' habits?
I did see some similar posts but none of them is helpful... and in case it helps:
I'm adding ZSESSIONID:apikey in my request header, instead of user /
password to authenticate, so I believe no security token is needed
(https://comm.support.ca.com/kb/api-key-and-oauth-client-faq/kb000011568)
url starts with https://rally1.rallydev.com/slm/webservice/v2.0/
issue is fixed after clearing cookies for
https://rally1.rallydev.com/, but somehow it appears again some time
later
I checked the cookie when the issue was reproduced, and found one with name of ZSESSIONID and its value became something else rather than the apikey. Not sure if that matters though...
code for request:
function initXHR(method, url, apikey, cbFunc) {
let httpRequest = new XMLHttpRequest();
...
httpRequest.open(method, url);
httpRequest.setRequestHeader('Content-Type', ' application\/json');
httpRequest.setRequestHeader('Accept', ' application\/json');
httpRequest.setRequestHeader('ZSESSIONID', apikey);
httpRequest.onreadystatechange = function() {
...
};
return httpRequest;
}
...
usReq = initXHR ('POST', baseURL+'hierarchicalrequirement/create', apikey, function(){...});
Anyone has any idea / suggestion? Thanks a million!
I've seen this error when the API key had both read-only and full-access grants configured. I would start by making sure your key only has the full-access grant.

Refresh token giving invalid grant

I am running into an issue with one single user's refresh workflow for Google OAuth. I am correctly scoping for offline access and am storing that. Every 60 minutes, when needed, I retrieve a new access_token. Code has not changed, but what is odd is that when he first went through the authorization process it worked for about 3 days. Then we were running this issue, so I made him revoke access and go through the authorization again. This only lasted for 3 days once again.
client_id ="xxxxx.apps.googleusercontent.com"
client_secret ="yyyyyyyy"
refresh_token ="zzzzzzzz"
response = oauth2a.RefreshToken(client_id,client_secret,refresh_token)
def RefreshToken(client_id, client_secret, refresh_token):
params = {}
params['client_id'] = client_id
params['client_secret'] = client_secret
params['refresh_token'] = refresh_token
params['grant_type'] = 'refresh_token'
request_url = AccountsUrl('o/oauth2/token')
response = urllib.urlopen(request_url, urllib.urlencode(params)).read()
return json.loads(response)
The response is always {u'error': u'invalid_grant'}. I have attempted this on three different machines, so the NTP time sync is not the issue as well. All other user's refresh works fine. I am also never asking for a refresh_token again, so I know I'm not running into that 25 refresh_token limit. This is looking like it's a bug on the gmail side, is there any way that I can proceed to try to fix this?

RestKit - Repeat request if auth timeout

I'm talking to a .NET Web API 2 service, using it's default "Individual User Accounts" authentication. I'm using RestKit 0.22.0.
My issue is that when a session timeout occurs, I want to have the iOS app re-authenticate with the stored credentials and then replay the request. The only way I've found to do this is like this - asked a year ago. However I do not think that the answer should be to check if the status code is 401, re-authenticate, retry the request in every failure block. As that's just a lot of copy and pasting!
Is there a better way to accomplish what I want?
Call a common method from the failure block which takes the required inputs. Preferably you might want to have multiple common methods which are capable of verifying the response details and restarting the process automatically (so 1 for GET, 1 for POST, ...).
Pseudo code
- (void)do something with this info:
{
... calculate method specifics then call general method ...
[self getObjectsAtPath:urlArg parameters:p success:s];
}
- (void)getObjectsAtPath:urlArg
parameters:p
success:s
{
[RK getObjectsAtPath:urlArg
parameters:nil
success:
{ -- Yay -- call success callback
s();
}
failure:
{ -- Humph -- retry
... do auth updates, then retry ...
[self getObjectsAtPath:urlArg parameters:p success:s];
}
}

Symfony Extend Authentication Timeout on Request

My thinking was that Symfony2 would extend the ExpireAt on each page request made during the authenticated session. So if the timeout was 100 seconds and you made a page request, the new ExpireAt would be time() + 100. This "use it or lose it" authentication functionality is similar to what you get on a banking website.
The default functionality seems to be when the session timeout is set to 100 in the config.yml, the user only has 100 seconds to do what they can.
I don't think this will be to hard to implement but where should it be done? My first guess is in the isEqualTo method. Once you can determine the user is authentic you can re-up their expireAt. Or does the cookie need to be modified?
The answer lies in the refreshUser method of the UserProvider and the isEqualTo method of the UserClass.
The isEqualTo method tells the user provider whether to refreshUser(UserInstance user).
Step1 : isEqualTo() returns false; (as your understanding grow, so can this logic. But essentially, this triggers refreshUser().
In all the basic user provider examples, the refreshUser & loadUserByUsername are identical. The to do what I'm talking about, the refreshUser() needs to be a little different.
Step2 : modify refreshUser(UserInterface $user). What's being passed into this method is the original userClass. So the refreshUser is responsible for syncing the expiresAt or credentialsExpireAt
I use this logic in my refreshUser() to either extend the expiration date OR set it to the original expiration date (which is expired):
if( time() > $user->getCredentialsExpireAt() ){
$refreshedUser->setCredentialsExpireAt( $user->getCredentialsExpireAt() );
}