authenticate to SharePoint through OKTA from back-end service - sharepoint

I have a need to programmatically connect to a customer's SharePoint server that uses OKTA for authentication. I saw this post which looked promising, but cannot seem to get a valid session cookie back from OKTA.
I can successfully call the /api/v1/authn endpoint and get back a sessionToken, but when I turn around and call /api/v1/sessions?additionalFields=cookieToken with that session token, I always received a 403 - Forbidden, with the following json:
{
"errorCode": "E0000005",
"errorSummary": "Invalid Session",
"errorLink": "E0000005",
"errorId": "oaew0udr2ElRfCnZvBFt075SA",
"errorCauses": []
}
Assuming I can get this resolved, I'm not sure of the URL I should call with the cookieToken. Is the url an OKTA endpoint that will redirect to SharePoint or is it an SharePoint endpoint that will setup the session with the cookie?
Update:
I am able to call this okta endpoint -> /api/v1/sessions?additionalFields=cookieToken with my user credentials as json
{
"username": "user#email.com",
"password": "P#ssw0rd"
}
And am able to retrieve a one-time cookie token that can be used with this link to start a SAML session in a browser:
https://[mydomain].okta.com/login/sessionCookieRedirect?redirectUrl=[sharepoint site url]&token=[cookie token]
That works in a browser, the user is automatically authenticated and ends up in SharePoint. However, it seems that this session "setup" is at least partly achieved through javascript as executing the same link in a programmatic HTTP client (such as Apache HTTP Client) does not work. The http client is sent through a couple of redirects and ends up in the SharePoint site, but the user is not authenticated. The response is 403 - Forbidden with the following headers:
403 - FORBIDDEN
Content-Type -> text/plain; charset=utf-8
Server -> Microsoft-IIS/8.5
X-SharePointHealthScore -> 0
SPRequestGuid -> 0ecd7b9d-c346-9081-cac4-43e41f3b159a
request-id -> 0ecd7b9d-c346-9081-cac4-43e41f3b159a
X-Forms_Based_Auth_Required -> https://[sharepoint site]/_login/autosignin.aspx?ReturnUrl=/_layouts/15/error.aspx
X-Forms_Based_Auth_Return_Url -> https://[sharepoint site]/_layouts/15/error.aspx
X-MSDAVEXT_Error -> 917656; Access denied. Before opening files in this location, you must first browse to the web site and select the option to login automatically.
X-Powered-By -> ASP.NET
MicrosoftSharePointTeamServices -> 15.0.0.4709
X-Content-Type-Options -> nosniff
X-MS-InvokeApp -> 1; RequireReadOnly
Date -> Fri, 13 May 2016 15:02:38 GMT
Content-Length -> 13
I'm starting to wonder if this is a lost cause, that OKTA or SharePoint doesn't support programmatic authentication via SAML.

It's possible.
Here is what I did.
1) Get your sessionToken from Okta. You'll need an okta authorization token for that.
2) Do a HttpGet(sharepointEmbeddedLink + "?onetimetoken=" + sessionToken)
Also add this header: new BasicHeader(AUTHORIZATION, String.format("SSWS %s", OKTA_AUTHORIZATION_TOKEN);
3) Next you'll have to parse the html response and get the SAML Arguments: WRESULT, WCTX, WA
4) Next do this - take those 3 and create a string in this format "application/x-www-form-urlencoded". It will be something like this "wa=wsign1.0&wctx=somevalue&wresult=somevalue".
byte[] out = theStringAbove.getBytes;
int length = out.length;
URL url = new URL("https://login.microsoftonline.com/login.srf");
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection) con;
http.setRequestMethod("POST"); // PUT is another valid option
http.setDoOutput(true);
http.setInstanceFollowRedirects(true);
http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
http.setRequestProperty("User-agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1");
http.connect();
http.getOutputStream().write(out);
5) You'll have the saml Token in the response. You'll have to parse an html file again.
6) You'll get the sharepoint siteUrl in step3 or 4 and do this next :)
HttpPost httpPost = new HttpPost(siteUrl + "_forms/default.aspx?wa=wsignin1.0");
byte[] utf8TokenStringBytes = ("t=" + samlToken).getBytes(StandardCharsets.UTF_8);
HttpEntity entity = new ByteArrayEntity(utf8TokenStringBytes);
httpPost.setEntity(entity);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpPost.setHeader("User-agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1");
HttpResponse response = httpclient.execute(httpPost, httpContext);
If everyting is ok, you'll have some cookie headers that you can use :D

Related

AADB2C90088: The provided grant has not been issued for this endpoint

We are using custom policies for Sign in and reset password in Azure B2C, when user is resetting his password and after doing all the process, when user tries to login using new password and OTP, below error is getting displayed and then user is continuously asked for new access code.
HTTP/1.1 400 Bad Request
Cache-Control: private
Allow: OPTIONS,TRACE,GET,HEAD,POST
Content-Type: application/json; charset=utf-8
x-ms-gateway-requestid: a6264e6b-e73e-45e1-aab9-71c5916e1215
Access-Control-Expose-Headers: Content-Length, Content-Encoding
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: POST, OPTIONS
Set-Cookie: x-ms-cpim-trans=; domain=****; expires=Fri, 02-Sep-2011 12:14:12 GMT; path=/; SameSite=None; secure; HttpOnly
X-Frame-Options: DENY
Public: OPTIONS,TRACE,GET,HEAD,POST
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Date: Thu, 02 Sep 2021 12:14:12 GMT
Content-Length: 296
{"error":"invalid_grant","error_description":"AADB2C90088: The provided grant has not been issued for this endpoint. Actual Value : B2C_1A_MFA_phone_or_email and Expected Value : B2C_1A_PasswordReset\r\nCorrelation ID: ******\r\nTimestamp: 2021-09-02 12:14:12Z\r\n"}
When the user has changed his password and click continue, below requests generated and you can see first token request is successful, but it is again trying for second token request and getting failed with above error.
Network logs
What we are expecting here is that user should automatically get logged in, once he reset his password, rather then navigating back to log in screen and asking credentials again.
The issue is that you are using the refresh token (RT) from the Password Reset policy to fetch a new token, but you are using the RT against the Sign In policy.
You need to make sure you select the correct Account object in your MSAL cache and use that against the matching B2C policy in your acquireTokenSilent() call.
You can access accounts in your msal instance with instance.getAllAccounts(), it appears to append any new account object each time you make a loginRedirect invocation. You may need to select the correct account in the array when you pass in the account object to acquireTokenSilent
const accounts = instance.getAllAccounts();
const account = accounts[index];
const authResult = await instance.acquireTokenSilent({
scopes: config.authentication.scopes,
account: account
});
### Its my implementation in react ###
const [account, setAccount] = useState();
useEffect(() => {
if (props.authConfig) {
const cachedAccounts = instance.getAllAccounts();
let account;
if (cachedAccounts.length < 1) {
setAccount(undefined);
} else {
account = cachedAccounts.filter((cachedAccount) =>
cachedAccount.username)?.[0];
}
if (account) {
account.name = `${account.idTokenClaims.given_name}
${account.idTokenClaims.family_name}`;
setAccount(account);
}
} else {
setAccount(undefined);
}
}, [props.authConfig]);
We need to make sure we select the correct Account object in
the MSAL
cache and use that against the matching B2C policy in the
acquireTokenSilent() call.

Cannot create an Integrator Key Docusign

I kept getting the following error when using Docusign python API
The specified Integrator Key was not found or is disabled. An Integrator key was not specified
Exception when calling DocuSign API: (401)
Reason: Unauthorized
HTTP response headers: HTTPHeaderDict({'Cache-Control': 'no-cache', 'Content-Length': '165', 'Content-Type': 'application/json; charset=utf-8', 'X-DocuSign-TraceToken': '2818f346-79f7-4c81-a1e1-b8da0f5556a6', 'Date': 'Thu, 17 Jan 2019 17:52:40 GMT', 'Vary': 'Accept-Encoding', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'})
HTTP response body: b'{\r\n "errorCode": "PARTNER_AUTHENTICATION_FAILED",\r\n "message": "The specified Integrator Key was not found or is disabled. An Integrator key was not specified."\r\n}'
So I tried creating new Integrator keys, not really knowing what the callback URI should be or much about what I am doing.
I noticed that everytime I created a key, if I refreshed browser, status would go to 'Error' - anybody know how I can generate an Integrator Key that stays in status 'Demo' and that i can use to make API calls
Here is an example of how I am setting up integrator key:
EDIT
I created a new sandbox of my own, when I create an API key in there it doesn't go to Error, stays in status 'Demo'
API key config looks like
and code to call looks like
integrator_key = MY_KEY_FROM_SCREENSHOT
base_url = "https://demo.docusign.net/restapi"
oauth_base_url = 'account-d.docusign.com'
redirect_uri = 'http://localhost:8000'
user_id = MY_EMAIL
#NOTHING HERE REALLY
private_key_filename = os.path.join(BASE_DIR, "keys/docusign_private_key.txt")
oauth_login_url = api_client.get_jwt_uri(integrator_key, redirect_uri, oauth_base_url)
# configure the ApiClient to asynchronously get an access token and store it
#api_client.configure_jwt_authorization_flow(private_key_filename, oauth_base_url, integrator_key, user_id, 3600)
docusign.configuration.api_client = api_client
auth_api = AuthenticationApi()
try:
login_info = auth_api.login(api_password='true', include_account_id_guid='true')
Hmmm I don't know why the Integration Key's status is changing to "Error."
A couple of ideas:
When adding a Redirect URI, include http:// or https:// at the start of the URI. Eg, enter http://127.0.0.1:8000/tools/ds_api
Don't click the Review Transactions option of the Actions drop down. That should only be done when you are ready for the Go-Live test.

Bad request on oauth/token

I try to use JWT Authentication but the API returns 400 Bad request {"error":"invalid_request"}.
Headers :
POST https://account-d.docusign.com/oauth/token HTTP/1.1
Connection: Keep-Alive
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Body :
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=XXXX
The JWT token is well formatted and contains as body :
iss = _clientIntegratorKey,
sub = "628c4cc3-d36e-4a6b-80bf-b7ccb97d842c",
iat = (long)(now - new DateTime(1970, 1, 1)).TotalSeconds,
exp = (long)(now.AddSeconds(3600) - new DateTime(1970, 1, 1)).TotalSeconds,
aud = "account-d.docusign.com",
scope = "signature"
What am i missing ?
I used my own RSA function that not encrypt with the right cypher algorithm.
Now I use a library (c# dotnet core : RSACryptoServiceProvider) to do it and it works like a charm.

After login WKWebView Session Logout in iOS

In my app, I want to do login using WKWebView and then all further request to server is done.
I'm able to perform successful login using WKWebView. On it's success I get session information. I had implemented it previously using UIWebView and it was working properly. All my further web service call were working fine in UIWebView.
Now when I implemented login with WKWebView it is successfully login but when i hit different link (URL) it gives me logout response every time and I'm trying to call service using Cookies and , it's not giving me proper response as session information are not being passed.
Is there any way, I can store those session information of WKWebView
Any help will be appreciated. Please help!
Here is the code where i m set cookies : -
*{
// Set iPad cookie for our requests
NSString* dotDomain = [NSString stringWithFormat:#".%#", CookieDomain];
NSDictionary* newCookieDict = [NSMutableDictionary
dictionaryWithObjectsAndKeys:
dotDomain, NSHTTPCookieDomain,
#"iPad", NSHTTPCookieName,
#"/", NSHTTPCookiePath,
#"1", NSHTTPCookieValue,
#"2040-1-1 00:00:00 -0700", NSHTTPCookieExpires,
nil];
NSHTTPCookie* newCookie = [NSHTTPCookie cookieWithProperties:newCookieDict];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:newCookie];
}
// Don't block cookies, so dosespot will work
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];*
Here is my Request HTTP Header and Response HTTP Header :-
*Request HTTP Header : {
"Accept-Encoding" = gzip;
Cookie = "cookie_test=1; cookie_test=1; CAKEPHP=jkn36knqoul2f14rebb8k5h882; iPad=1";
"User-Agent" = "iPad App";
}*
**Response HTTP Header : {
Connection = "Keep-Alive";
"Content-Encoding" = gzip;
"Content-Length" = 5668;
"Content-Type" = "text/html";
Date = "Tue, 10 May 2016 13:58:14 GMT";
"Keep-Alive" = "timeout=5, max=99";
Server = "Apache/2.2.22 (Ubuntu)";
Vary = "Accept-Encoding";
"X-Powered-By" = "PHP/5.3.10-1ubuntu3.15";
}**

Unable to authorize at Azure mobile app services using MobileServiceClient

I’ve been trying to implement Azure Active Directory authentication for my Web app at Mobile app.
Mobile app has been configured as described in this tutorial (used Alternative method).
My Azure Active Directory app settings:
SIGN-ON URL: https:// <mymobileappname>.azurewebsites.net/
App ID URI: https:// <mymobileappname>.azurewebsites.net/
Reply URL: https:// <mymobileappname>.azurewebsites.net/.auth/login/aad/callback
Also I’ve passed ClientID(b6da4c72-xxxx-xxxx-xxxx-e20d561b7906) and entityID(https:// sts.windows.net/e052874c-xxxx-xxxx-xxxx-afd774687ee8/) to mobile app authentication settings in the Azure portal and switched it ON.
At my Web app I do folowing:
Take token from Azure Active Directory
public string GetAADToken()
{
string clientID = "b6da4c72-xxxx-xxxx-xxxx-e20d561b7906";
string authority = "https://login.windows.net/<mytenant>";
string resourceURI = "https://<mymobileappname>.azurewebsites.net/";
var appKey = <mysecretvalidkeytakenfromazureactivedirecoryapp>";
var authenticationContext= new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);
var clientCredential = new ClientCredential(clientID, appKey);
var authenticationResult = authenticationContext.AcquireToken(resourceURI, clientCredential);
return authenticationResult.AccessToken;
}
Authenticate with AAD token at Mobile app using MobileServiceClient(v2.0.1)
MobileServiceClient client = new MobileServiceClient("https://<mymobileappname>.azurewebsites.net/");
var token = new JObject();
token["access_token"] = GetAADToken();
var res = client.LoginAsync("aad", token).Result;
This code sends authentication request to my mobile app
{Method: POST, RequestUri: 'https://<mymobileappname>/.auth/login/aad', Version: 1.1, Headers:
{
X-ZUMO-INSTALLATION-ID: 904579fa-xxxx-xxxx-xxxx-02efc7ba2937
Accept: application/json
User-Agent: ZUMO/2.0
User-Agent: (lang=Managed; os=Windows; os_version=6.2.0.9200; arch=Win32NT; version=2.0.31217.0)
X-ZUMO-VERSION: ZUMO/2.0 (lang=Managed; os=Windows; os_version=6.2.0.9200; arch=Win32NT; version=2.0.31217.0)
Content-Type: application/json; charset=utf-8
Content-Length: 1129
}}
In the POST-body sends json with AAD token.
The same solution was used for azure mobile services and works fine, but for Mobile app service I always get: 401 'Unauthorized'.
What am I doing wrong?

Resources