New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Radius: How to handle the request for passcode - {"ErrorCode":"ITATS542I","ErrorMessage":"Enter PASSCODE"} #3
Comments
Hi, Could you try to catch this exception and then reauthenticate with the passcode ? |
Hi, I am struggling a bit on the re-authenticate with the Passcode. I am able to catch the exception, but after reauth it fails with invalid credential. code: import aiobastion
import asyncio
config = {'api_host': 'pvaa_host'}
async def main():
vault = aiobastion.EPV(serialized=config)
try:
await vault.login(username, password, 'radius')
except Exception as err:
if 'ITATS542I' in str(err):
passcode = input("Enter passcode: ")
try:
await vault.login(username, passcode, 'radius')
except Exception as err:
print(str(err))
async with vault as epv:
print(await epv.safe.list())
if __name__ == '__main__':
asyncio.run(main()) I suspect that it might be that the session is closed/cleared because of the 500 error? code added for test in cyberark.py, at line 118 ...
elif req.status == 500: #"ITATS542I"
try:
request_data = {"username": username, "password": 'passcode', "concurrentSession": True}
async with session.post(url, json=request_data, **self.request_params) as req:
tok = await req.text()
print(tok)
except Exception as err:
print(str(err))
else:
... |
Have tested some more, and I am able to get a successfull login when the Cookies are set when sending the second authentication for the passcode. Store the Cookies from the first login with username and password. BR |
Hi, Please see if it is something that can be added to the framework. BR __login_cyberark - line 105 async def __login_cyberark(self, username: str, password: str, auth_type: str) -> str:
assert self.__token is None
assert auth_type.upper() in ("CYBERARK", "WINDOWS", "LDAP", "RADIUS")
url, head = self.get_url("API/Auth/" + auth_type + "/Logon")
request_data = {"username": username, "password": password, "concurrentSession": True}
try:
if auth_type.upper() == "RADIUS":
global radiussession
try:
radiussession
except NameError:
session = self.get_session()
else:
session = radiussession
else:
session = self.get_session()
async with session.post(url, json=request_data, **self.request_params) as req:
if req.status != 200:
if req.status == 403:
raise CyberarkException("Invalid credentials ! ")
elif req.status == 409:
raise CyberarkException("Password expired !")
else:
try:
raise CyberarkException(await req.text())
except Exception as err:
if 'ITATS542I' in str(err): # and req.status == 500
radiussession = session
raise CyberarkException(req.status, str(err))
else:
await self.close_session()
# Old session reused ?
raise CyberarkException(f"Unknown error, HTTP {str(req.status)}, ERR : {str(err)}")
tok = await req.text()
# Closing session because now we are connected and we need to update headers which can be done
# only by recreating a new session (or passing the headers on each request)
await session.close()
radiussession = None
return tok.replace('"', '')
# Cleaning password after authentication
self.__password = ""
except (ConnectionError, TimeoutError):
raise CyberarkException("Network problem connecting to PVWA")
except Exception as err:
raise CyberarkException(err) Test code import aiobastion
import asyncio
pvwa_host = 'pam-host'
username = 'user'
password = 'password'
authtype = 'Radius'
config = {'api_host': pvwa_host}
async def main():
vault = aiobastion.EPV(serialized=config)
try:
await vault.login(username, password, authtype)
except Exception as err:
if 'ITATS542I' in str(err):
passcode = input("Enter passcode: ")
try:
await vault.login(username, passcode, authtype)
except Exception as err:
print('Error:',str(err))
else:
print('Error:',str(err))
try:
async with vault as epv:
print('Token:',await epv.check_token())
try:
safes = await epv.safe.list(details=True)
print(safes)
except Exception as err:
print('Error:',str(err))
except Exception as err:
print('Error:',str(err))
if __name__ == '__main__':
asyncio.run(main()) |
Hi Bjorn-Kare, I prefer not handling "normal use cases" with exceptions if possible, it doesn't feel natural for me. I have created a new branch called "radius", could you try with the cyberark.py in it ? The idea is to call the login function with your pin code and your passcode. The login function the redirects you to the "__chall_response_login" function to achieve the authent with both requests.
Try it and tell me what happens, if you have troubles and if you are stuck i will try to reproduce the "challenge response" login in my lab. Greetings, |
Hi Gautier, Thank you. You are of-course correct in not handling normal use cases with exceptions, that is what I would like . Just did a "how can I get it to work first", and then maybe try to improve the code afterwards. And I am not an experienced Python-coder :-) The new radius branch works when I have the passcode up-front. I use my password as pincode. It seems that it will not work when the passcode is sent/requested as a challenge/response to the user. Even if we are moving towards using apps with confirmation for the Radius, there will still be use cases where the user needs to wait for and enter the passcode as a challenge/response. Thanks |
Hi Gautier, Tested a bit more where I catch the 'ITATS542I' exception and then enter the passcode. For the simple test user that has a predefined passcode this also works, but the Cyberark logs it as an 'Authentication failure', twice. I can still list the user Safe, and get a "Event loop is closed" error. For a user that has a challenge/response passcode it fails with "Invalid credentials !". the Cyberark logs "Radius authentication failure... (Radius server reply: Passcode is incorrect or has expired)." A test with a fake passcode for the first login, and enter the challenge/response passcode inside if "ITATS542I" in response:
# Update request data
passcode = input("Enter passcode: ")
request_data = {"username": username, "password": passcode, "concurrentSession": True} This will work for running the scripts manually, but will not work when calling the login where the user enters the credentials in a web-page. BR |
Hi Bjorn-Kare, Sorry for the late reply, I was having trouble handling sessions correctly with issues that happen when calling asynchronous functions in synchronous functions. I've just published a new version (0.0.14) that raise a ChallengeResponseException at the first login. So you can catch it and reauthenticate with the passcode. Could you please try it and tell me if it's ok ? Best regards, |
Hi Gautier, Thank you, it seems to work as wanted. I get an error after login and getting the safes (see at end of post), but that might be the test-code I use. I might have some other suggestions/requests expanding aiobastion, will get back to them later. Thank you Code used for testing: import aiobastion
import asyncio
import getpass
pvwa_host = 'pam-host'
authtype = 'Radius'
username = 'username'
password = getpass.getpass()
config = {'api_host': pvwa_host}
async def main():
vault = aiobastion.EPV(serialized=config)
try:
await vault.login(username, password, authtype)
except Exception as err:
passcode = input("Enter passcode: ")
await vault.login(username, passcode, authtype)
async with vault as epv:
safes = await epv.safe.list(details=True)
print(safes)
if __name__ == '__main__':
asyncio.run(main()) Error after running code:
|
Glad to hear that it's working as expected! For your error, try this => encode/httpx#914 (comment) if __name__ == '__main__':
if sys.version_info[0] == 3 and sys.version_info[1] >= 8 and sys.platform.startswith('win'):
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.run(main()) I tried with your code and it's working fine on my end but i'm running python3.11 where this bug may have been fixed. I am listening to your suggestions / requests, please do not hesitate to send me your criticism! Best regards, |
Thank you, that solved the error. Thank you for getting the Radius to work. Br |
Hi, To catch the The only exception I seem to get is Or have I misunderstood? Best Regards |
Hi, Please have a try and tell me. |
Thank you, I can use the "ChallengeResponseException" now. BR |
Hi,
Testing with Radius as Authentication Method.
After the username and password is verified, the Radius server sends a passcode for the user to enter.
Cyberark returns
{"ErrorCode":"ITATS542I","ErrorMessage":"Enter PASSCODE"}
to get passcode from the user.Do you have an example on how to catch this,
and get (wait for) the passcode from the user and finish the authentication?
BR
Bjorn-Kare
The text was updated successfully, but these errors were encountered: