Python Request getting redirected to SSO - python-requests

Hope everyone reading this is doing well.
I am working on fetching recovery keys from JAMF through Python, however, it seems like the request is getting redirected to an SSO webpage, which says that javascript is not enabled, so I don't get my session token for a further request.
I am using this repo - https://github.com/mikemackintosh/py-keysword
Code:
def getSessionToken():
jar = cookielib.CookieJar()
s = requests.Session()
s.cookies = jar
resp = s.post('{}/?failover'.format(JAMF_HOST), cookies=jar, data={'username':JAMF_USERNAME, 'password':JAMF_PASSWORD, 'resetUsername':''})
if resp.status_code != 200:
print("Failed to Authenticate!")
exit(1)
params = {"id": 29, "o": "r", "v": "management"}
resp = s.get('{}/legacy/computers.html'.format(JAMF_HOST), params=params, cookies=jar)
session_token = ""
print(resp.content)
# TODO: add error checking here
for line in resp.content.splitlines():
if b"session-token" in line:
return line.encode('utf-8').translate(None, '<>"').split('=')[-1]
print("Unable to find session token")
getSessionToken()
I then get this HTML response in resp.content with the SAMLRequest value and the continue button.
"b'\n\n \n \n \n \n \n Note: Since your browser does not support JavaScript,\n you must press the Continue button once to proceed.\n \n "
Any clue how I can go about to circumvent this? I think I need a way to 'click' the button through my script to then get my session token but I am not sure how to go about that. Thanks!

Related

Passing files in POST using Requests in Python

I'm getting below error when making a requests call post method
{'detail': [{'loc': ['body', 'files'], 'msg': 'field required', 'type': 'value_error.missing'}]}
I tried
response = requests.post("url",headers={mytoken},params=p,files=files)
files = { "file 1": open("sample.pdf",'rb'), "file 2":open("sample11.pdf",'rb')}
I want to get 200 status but I'm getting 422 validation error. Any Idea Why? Its for API Testing purpose, Im new to this I've been debugging this for whole day but still couldn't figure out.
It is not clear from the question what kind of a request the server is expecting. Also, its not clear the exact code snippet you are using too.
From the question, the snippet looks like as follows,
response = requests.post("url",headers={mytoken},params=p,files=files)
files = { "file 1": open("sample.pdf",'rb'), "file 2":open("sample11.pdf",'rb')}
if so, that means you are reading files after you send the request, may be thats why the server complained about missing files field.
See the below example on how you can send two files to an endpoint expecting files.
import requests
import logging
logger = logging.getLogger(__name__)
post_url = "https://exampledomain.local/upload"
file1 = open("sample1.pdf", "rb")
file2 = open("sample2.pdf", "rb")
files = {"file1": file1, "file2": file2}
headers = {"Authorization": "Bearer <your_token_here>"}
params = {"file_type": "pdf"}
response = requests.post(post_url, files=files, headers=headers, params=params)
file1.close()
file2.close()
logger.debug(response.text)

Graph API - ResourceNotFound when creating a user

Ive been trying to do this for a couple of days now and ive double checked everything against examples and tried searching my error response but im not able to come up with anything.
Ive succesfully added graph api calls to my appplication already, when I do a GET on the /users endpoint it returns my AD users just fine, the code below is what I am doing to try and create the user but every time i get ResourceNotFound response.
It may we worth noting that at first I was getting an error message where it wasnt stating the resource it couldnt find, but now the error message is showing 'Resource 'User_' does not exist...'
The GUID changes every time suggesting that it is creating that object and then trying to do something with it but then failing on the API somewhere.
Create User Function -
Public Function CreateUser(user As User) As String
Dim app As IConfidentialClientApplication = MsalAppBuilder.BuildConfidentialClientApplication(ClaimsPrincipal.Current)
Dim accountId = ClaimsPrincipal.Current.GetMsalAccountId()
Dim account = app.GetAccountAsync(accountId).Result
Dim result As AuthenticationResult
Dim scopes As String() = {"https://graph.microsoft.com/.default"}
Try
result = app.AcquireTokenSilent(scopes, account).ExecuteAsync().Result
Catch msalEx As MsalUiRequiredException
Return msalEx.Message
Catch ex As Exception
result = app.AcquireTokenForClient(scopes).ExecuteAsync().Result
End Try
Dim client = New HttpClient()
Dim request As New HttpRequestMessage(HttpMethod.Post, "https://graph.microsoft.com/v1.0/users")
request.Headers.Authorization = New AuthenticationHeaderValue("Bearer", result.AccessToken)
Dim json = JsonConvert.SerializeObject(user)
request.Content = New StringContent(json, Encoding.UTF8, "application/json")
Dim response = client.SendAsync(request).Result
If response.Content IsNot Nothing Then
Dim responseString = response.Content.ReadAsStringAsync().Result
Return responseString
End If
Return ""
End Function
Something else I noticed is that the app never contains any users so the scope only token is always called.
After posting here I also requested help from the microsoft support team.
They suggested that i use the graph explorer to try again, so after doing both that and re-sending my request in Insomnia I did in fact get a successful response when using the graph explorer and still BadRequest from Insomnia and code.
The difference between these requests was the Request Body.
What I initially built was using the code sample provided in the graph documentation here (Example 1) - https://learn.microsoft.com/en-us/graph/api/user-post-users?view=graph-rest-1.0&tabs=http
To save you some time this is what it looks like -
POST https://graph.microsoft.com/v1.0/users
Content-type: application/json
{
"accountEnabled": true,
"displayName": "Adele Vance",
"mailNickname": "AdeleV",
"userPrincipalName": "AdeleV#contoso.onmicrosoft.com",
"passwordProfile" : {
"forceChangePasswordNextSignIn": true,
"password": "xWwvJ]6NMw+bWH-d"
}
}
And this is what the request body looks like in graph explorer -
{
"accountEnabled": true,
"city": "Seattle",
"country": "United States",
"department": "Sales & Marketing",
"displayName": "Melissa Darrow",
"givenName": "Melissa",
"jobTitle": "Marketing Director",
"mailNickname": "MelissaD",
"passwordPolicies": "DisablePasswordExpiration",
"passwordProfile": {
"password": "b85dba0d-be1b-a59a-8332-6821b138674d",
"forceChangePasswordNextSignIn": false
},
"officeLocation": "131/1105",
"postalCode": "98052",
"preferredLanguage": "en-US",
"state": "WA",
"streetAddress": "9256 Towne Center Dr., Suite 400",
"surname": "Darrow",
"mobilePhone": "+1 206 555 0110",
"usageLocation": "US",
"userPrincipalName": "MelissaD#{domain}"
}
After changing my code model to match the second request body I now get a successful response in code, and to test the theory I left my old request body in Insomnia and resent the request with a fresh token and it return BadRequest whilst the code returned Success.
I'm not 100% sure what the missing properties are, perhaps just password policies. If Microsoft give me more insight I will update here.
Hopefully this provides someone else with some insight as I really struggled to find information on this one myself.
Try out a few things -
As Tim suggested using the same token and JSON Content and see if you can leverage Postman and call the same API to validate your JSON(request body), URL, and token.
Use jwt.ms and check if your token has all necessary claims.
Make sure you have given required permission to your App.
If you still face same problem, do revert with client-request-id and timestamp so that I can check it better.
Thanks.

python fastapi redirect and authenticate

I'm trying to authenticate the user after visiting the registration link
(link example: http://127.0.0.1:8000/confirm-email?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9F)
My code:
#app.get("/confirm-email", status_code=200, )
def confirm_email(
token: str = fastapi.Query(..., min_length=64, max_length=256,
db: Session = fastapi.Depends(database.get_db)):
if user := crud.read_user_by(db, column='current_token', value=token):
if user.created_datetime + timedelta(minutes=30) > datetime.now(): # TODO change minutes to days
return fastapi.responses.RedirectResponse(
url="http://127.0.0.1:8000/users/me",
headers={"access_token": token, "token_type": "bearer"})
else:
raise fastapi.HTTPException(
status_code=fastapi.status.HTTP_410_GONE,
detail="Confirmation link is expired")
else:
raise fastapi.HTTPException(
status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
detail="Wrong token")
#app.get("/users/me")
def read_users_me(token: str = fastapi.Depends(oauth2_scheme),
db: Session = fastapi.Depends(database.get_db)):
try:
return services.get_user_by_token(db=db, token=token)
except Exception as e:
raise fastapi.HTTPException(
status_code=fastapi.status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
But every time I'm failing when trying to use /users/me endpoint (getting 401 error, UNAUTHORIZED).
Maybe I put the token in the wrong place or using wrong headers?
If using OAuth 2.0 and wanting to set the access_token in a request, tipically, it goes into the Authorization header like the example in the RFC: Authorization: Bearer mF_9.B5f-4.1JqM - in the example, mF_9.B5f-4.1JqM would be the value of the token.
It seems to me that you are accessing the users/me endpoint with the headers access_token: [token value] and token_type: "bearer". Instead, I believe the following header should be set: Authorization: Bearer [token value]
After a little researching, I figured out that redirection by specification can't have authorization headers (browser/client will just ignore it mainly). So even if headers are correct - it's nonsense. One possible solution to use URL.

API authentication in R - unable to pass auth token as header

I am looking to do a simple GET request (from the Aplos API) in R using the httr package. I'm able to obtain a temporary token by authenticating with an API key, but then I get a 401 "Token could not be located" once trying to use the token to make an actual GET request. Would appreciate any help! Thank you in advance.
AplosURL <- "https://www.aplos.com/hermes/api/v1/auth/"
AplosAPIkey <- "XYZ"
AplosAuth <- GET(paste0(AplosURL,AplosAPIkey))
AplosAuthContent <- content(AplosAuth, "parsed")
AplosAuthToken <- AplosAuthContent$data$token
#This is where the error occurs
GET("https://www.aplos.com/hermes/api/v1/accounts",
add_headers(Authorization = paste("Bearer:", AplosAuthToken)))
This is a Python snippet provided by the API documentation:
def api_accounts_get(api_base_url, api_id, api_access_token):
# This should print a contact from Aplos.
# Lets show what we're doing.
headers = {'Authorization': 'Bearer: {}'.format(api_access_token)}
print 'geting URL: {}accounts'.format(api_base_url)
print 'With headers: {}'.format(headers)
# Actual request goes here.
r = requests.get('{}accounts'.format(api_base_url), headers=headers)
api_error_handling(r.status_code)
response = r.json()
print 'JSON response: {}'.format(response)
return (response)
In the python example, the return of the auth code block is the api_bearer_token which is base64 decoded and rsa decrypted (using your key) before it can be used.
...
api_token_encrypted = data['data']['token']
api_bearer_token = rsa.decrypt(base64.decodestring(api_token_encrypted), api_user_key)
return(api_bearer_token)
That decoded token is then used in the api call to get the accounts.
The second issue I see is that your Authorization header does not match the example's header. Specifically, you are missing the space after "Bearer:"
headers = {'Authorization': 'Bearer: {}'.format(api_access_token)}
vs
add_headers(Authorization = paste("Bearer:", AplosAuthToken)))
Likely after addressing both of these you should be able to proceed.

Error HTTP 404.11 passing account activation Token by querystring

I'm trying to implement password reset funcionallity. I use the ASP.NET Identity.
I am using the UserManager.GetConfirmationToken that returns a token like this:
UW/cj4xUj08kiGCntnWs7z1eUcWlyfNczH5IZfvf0ScTi4L1jgdkkus/Zb5ROJOWb%2b1XAVRSiBUvVGnESfEyauDDa4u%2bPDUH6D/CIpwPcFYRvLi%2b%2bq6f%2bRIhKHRTsGMV0y8lXpSZ5VqySWGSSaW9kofGage/IjW4HrvONeEtA4Szov3u7HgmqEUf0yzgivJ0
Then, I compose my URL and I send it by Email to the registered user. The url to activate the account is like this:
http://localhost:4322/Account/Confirm/UW/cj4xUj08kiGCntnWs7z1eUcWlyfNczH5IZfvf0ScTi4L1jgdkkus/Zb5ROJOWb%2b1XAVRSiBUvVGnESfEyauDDa4u%2bPDUH6D/CIpwPcFYRvLi%2b%2bq6f%2bRIhKHRTsGMV0y8lXpSZ5VqySWGSSaW9kofGage/IjW4HrvONeEtA4Szov3u7HgmqEUf0yzgivJ0
When I click, this error occurs:
Error HTTP 404.11 - Double escape sequence issue
The underlying problem here is trying to add confirmation code to the path. Whereas it should be sent via querystring.
So it should be like this
http://localhost:4322/Account/Confirm?code=UW/cj4xUj08kiGCntnWs7z1eUcWlyfNczH5IZfvf0ScTi4L1jgdkkus/Zb5ROJOWb%2b1XAVRSiBUvVGnESfEyauDDa4u%2bPDUH6D/CIpwPcFYRvLi%2b%2bq6f%2bRIhKHRTsGMV0y8lXpSZ5VqySWGSSaW9kofGage/IjW4HrvONeEtA4Szov3u7HgmqEUf0yzgivJ0
This will save day whose tries to solve this problem.
I found the answer at this comment : http://blogs.msdn.com/b/webdev/archive/2014/03/20/test-announcing-rtm-of-asp-net-identity-2-0-0.aspx?PageIndex=1#comments Thanks to pranav rostgi
You may need to encode URL using httputility.urlencode
Your token contains / symbols wich are being parsed as a path to some server page. You can either encode it somehow (maybe base64) and use as query string parameter like ...?token=.... Or change token generations so it will contain only good symbols
Make sure you aren't double encoding the token, so you can do something like this to send the email:
string code = await UserManager.GetConfirmationToken(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking this link: link");

Resources