I have a SAML implementation which works fine with JumpCloud, OneLogin and other providers, however integration with Microsoft Azure AD is proving difficult. We received the error
AADSTS75005: The request is not a valid Saml2 protocol message.
Whenever we send our requests over. I have tried the solutions mentioned here and here but neither fixes the issue for us.
My code to create the SAML Request, which opens in a new window via some Javascript is:
Using sw As StringWriter = New StringWriter()
Dim xws As XmlWriterSettings = New XmlWriterSettings()
xws.OmitXmlDeclaration = True
Dim assertionUrl As String = "OUR URL"
Dim issuer As String = "OUR ISSUER TEXT"
dim id as string = "_" + System.Guid.NewGuid().ToString()
dim issue_instant as string = DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
Using xw As XmlWriter = XmlWriter.Create(sw, xws)
xw.WriteStartElement("samlp", "AuthnRequest", "urn:oasis:names:tc:SAML:2.0:protocol")
xw.WriteAttributeString("ID", id)
xw.WriteAttributeString("Version", "2.0")
xw.WriteAttributeString("IssueInstant", issue_instant)
xw.WriteAttributeString("ProtocolBinding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
xw.WriteAttributeString("AssertionConsumerServiceURL", assertionUrl)
xw.WriteStartElement("saml", "Issuer", "urn:oasis:names:tc:SAML:2.0:assertion")
xw.WriteString(issuer)
xw.WriteEndElement()
xw.WriteStartElement("samlp", "NameIDPolicy", "urn:oasis:names:tc:SAML:2.0:protocol")
xw.WriteAttributeString("Format", "urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified")
xw.WriteAttributeString("AllowCreate", "true")
xw.WriteEndElement()
xw.WriteStartElement("samlp", "RequestedAuthnContext", "urn:oasis:names:tc:SAML:2.0:protocol")
xw.WriteAttributeString("Comparison", "exact")
xw.WriteStartElement("saml", "AuthnContextClassRef", "urn:oasis:names:tc:SAML:2.0:assertion")
xw.WriteString("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")
xw.WriteEndElement()
xw.WriteEndElement() ' RequestedAuthnContext
xw.WriteEndElement()
End Using
If (format = AuthRequestFormat.Base64)
Dim toEncodeAsBytes As Byte() = System.Text.ASCIIEncoding.ASCII.GetBytes(sw.ToString())
Return System.Convert.ToBase64String(toEncodeAsBytes)
End If
Return Nothing
End Using
We then redirect the user to: https://login.microsoftonline.com/OUR_APP_ID/saml2?SAMLRequest= followed by the encoded string
I have base64decoded my result, and read it as a raw string and the XML appears valid to me. I have even gone so far as to take the example Request from Azure AD and hard-coded my implementation to that, with replaced issuer/instant/id etc. This leads me to believe it is an encoding issue in my request. However, the changed encoding in Dushyant Gill's answer does not resolve my problem either.
I've found various other forum posts where other software vendors have mentioned that they have had to apply changes to their SAML implementations when their customers have complained that it didn't work with Azure - however I've yet to find what their resolution was.
If you are using HTTP redirect binding (which is suggested by
We then redirect the user to
) , then the SAMLRequest has to be encoded using DEFLATE encoding. Please see section 3.4.4 of http://docs.oasis-open.org/security/saml/v2.0/saml-bindings-2.0-os.pdf
Related
I have just started reading up docusign and have to implement it in my project using PHP. The requirement being, once user accepts the offer, he is directed to the document for signing. I understood the template and envelop creation but am stuck at the first step of authorization. I used the Legacy Header Authentication which is easy and works. But they are discouraging using this method anymore. So what to do instead of this?
Thanks in advance.
Is your application used to send out the request for signing?
If so, then the user of your application should probably have their own account on DocuSign. You should use OAuth authorization code grant to let your app's user login and send out the signing request.
For example, an employee uses your app to send out offer letters. In this case, your employee would authenticate himself to DocuSign via your app using OAuth Authorization Code Grant.
Or is the user of your application the signer who will be agreeing to something via DocuSign? If so then your app needs to create an envelope to be signed by the signer. Since the user of your application in this case is not a member of your company/organization, you need your app to impersonate someone who is a member of your org.
In this case, your app can use JWT authentication with impersonation to act on behalf of someone.
For example, your application is used by potential new employees to agree to the offered employment contract. In this case, the user of your app (the new employee) doesn't have a DocuSign login. So your app impersonates (using the JWT flow) an HR person in your company. Your app then, on behalf of the HR person, enables the new employee to sign the offer letter or generate new letter that will be sent for signing via DocuSign.
If JWT authentication fits your user case, we have a code example for PHP. See https://github.com/docusign/eg-01-php-jwt
We also have an Authorization code grant example for PHP.
I tried "rolling my own" JWT authentication, but gave up. I have found that Chilkat (chilkatsoft.com) works well:
Function Authenticate(SenderEmail2 As String) As Boolean
'MsgBox("AuthToDocuSign.Authenticate()") 'IHF 04/28/22
Authenticate = False
Dim oauth2 As New Chilkat.OAuth2
Dim success As Boolean
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12 'IHF 05/01/22
' This should be the port in the localhost Redirect URI for your app defined in the Docusign developer portal.
' The Redirect URI would look like "http://localhost:3017/" if the port number is 3017.
oauth2.ListenPort = 8080
' For developer sandbox environment, authorization endpoint is https://account-d.docusign.com/oauth/auth
' For production platform, authorization endpoint is https://account.docusign.com/oauth/auth
oauth2.AuthorizationEndpoint = "https://account.docusign.com/oauth/auth"
oauth2.TokenEndpoint = "https://account.docusign.com/oauth/token"
oauth2.ClientId = "c55048e7-fae1-4ad1-b223-258fce040f57" 'PROD. Also known as Integration Key
' This is your secret key for the authorization code grant.
oauth2.ClientSecret = "f1ddad37-a731-44b1-9679-e7f4268ec4a2" 'PROD. Also known as Secret Key [Fix 04/28/22] ?
oauth2.Scope = "signature"
'oauth2.Scope = "signature impersonation" 'IHF 02/14/22
oauth2.RedirectAllowHtml = "<html><head><meta http-equiv='refresh' content='0;url=https://app.docusign.com'></head><body>Thank you for allowing access.</body></html>" 'PROD. appdemo.docusign.com in DEV
' Begin the OAuth2 three-legged flow. This returns a URL that should be loaded in a browser.
Dim url As String = oauth2.StartAuth()
If (oauth2.LastMethodSuccess <> True) Then
Debug.WriteLine(oauth2.LastErrorText)
Exit Function
End If
ServicePointManager.Expect100Continue = True 'IHF 02/28/22
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 'IHF 02/28/22
Process.Start("C:\Program Files\Internet Explorer\iexplore.exe", url)
' Now wait for the authorization.
' We'll wait for a max of 30 seconds.
Dim numMsWaited As Integer = 0
While (numMsWaited < 30000) And (oauth2.AuthFlowState < 3)
oauth2.SleepMs(100)
numMsWaited = numMsWaited + 100
End While
' If there was no response from the browser within 30 seconds, then
' the AuthFlowState will be equal to 1 or 2.
' 1: Waiting for Redirect. The OAuth2 background thread is waiting to receive the redirect HTTP request from the browser.
' 2: Waiting for Final Response. The OAuth2 background thread is waiting for the final access token response.
' In that case, cancel the background task started in the call to StartAuth.
If (oauth2.AuthFlowState < 3) Then
oauth2.Cancel()
Debug.WriteLine("No response from the browser!")
Exit Function
End If
' Check the AuthFlowState to see if authorization was granted, denied, or if some error occurred
' The possible AuthFlowState values are: 3: Completed with Success. 4: Completed with Access Denied. 5: Failed Prior to Completion.
If (oauth2.AuthFlowState = 5) Then
Debug.WriteLine("OAuth2 failed to complete.")
Debug.WriteLine(oauth2.FailureInfo)
Exit Function
End If
If (oauth2.AuthFlowState = 4) Then
Debug.WriteLine("OAuth2 authorization was denied.")
Debug.WriteLine(oauth2.AccessTokenResponse)
Exit Function
End If
If (oauth2.AuthFlowState <> 3) Then
Debug.WriteLine("Unexpected AuthFlowState:" & oauth2.AuthFlowState)
Exit Function
End If
Debug.WriteLine("OAuth2 authorization granted!")
Debug.WriteLine("Access Token = " & oauth2.AccessToken)
accessToken = oauth2.AccessToken 'IHF 02/14/22
' Get the full JSON response:
Dim json As New Chilkat.JsonObject
json.Load(oauth2.AccessTokenResponse)
json.EmitCompact = False
Debug.WriteLine(json.Emit())
' Save the JSON to a file for future requests.
Dim fac As New Chilkat.FileAccess
fac.WriteEntireTextFile("qa_data/tokens/docusign.json", json.Emit(), "utf-8", False)
Authenticate = success
End Function 'IHF 04/28/22
I have been using DocuSign SOAP based API service to parse the XML that DocuSign posts for each recipient/envelope status updates.
Within .net web application, here is how I am parsing the XML.
Using sr As New StreamReader(FileName)
Dim xml As String = sr.ReadToEnd()
Dim reader As XmlReader = New XmlTextReader(New StringReader(xml))
Dim serializer As New XmlSerializer(GetType(DocuSignServ.DocuSignEnvelopeInformation), "http://www.docusign.net/API/3.0")
Dim envelopeInfo As DocuSignEnvelopeInformation = TryCast(serializer.Deserialize(reader), DocuSignEnvelopeInformation)
End Using
I would like to know if I can parse the XML with RESTful API here. I could not find a way to convert XML to an object based upon RESTful API.
I tried something like this,
Using sr As New StreamReader(FileName)
Dim xml As String = sr.ReadToEnd()
Dim reader As XmlReader = New XmlTextReader(New StringReader(xml))
Dim serializer As New XmlSerializer(GetType(DocuSign.eSign.Model.EnvelopesInformation), "http://www.docusign.net/API/3.0")
Dim envelopeInfo As DocuSign.eSign.Model.EnvelopesInformation = TryCast(serializer.Deserialize(reader), DocuSign.eSign.Model.EnvelopesInformation)
End Using
I am not able to convert the XML to an envelope object here.
Please advise,
Thanks,
Minal
No, the RESTful API works on different data model and you cannot parse DocuSign Connect XML with RESTful API data model.
I'm using Azure media services. I tried to obtain a SAS by creating a locator, and then getting the baseURI property of it. The SAS I got by doing that is:
https://rfsstorage.blob.core.windows.net/asset-02b45419-74fd-48cc-bdb8-dd66e0d88055
But is that really a SAS? Or is it something else? It certainly doesn't work with other code that I borrowed from the internet that expects a SAS.
Here is the few lines of code I used to obtain the SAS:
Public Sub OtainSAS(ByVal Filename As String)
Dim mediaServicesAccountName As String = ConfigurationManager.AppSettings("accountname")
Dim mediaServicesAccountKey As String = ConfigurationManager.AppSettings("accountkey")
Dim mediaCloud As New CloudMediaContext(mediaServicesAccountName, mediaServicesAccountKey)
Dim assetOptions As New AssetCreationOptions()
Dim asset = mediaCloud.Assets.Create(Filename, assetOptions)
Dim assetFile = asset.AssetFiles.Create(Filename)
Dim accessPolicy = mediaCloud.AccessPolicies.Create(Filename, TimeSpan.FromDays(3), AccessPermissions.Write Or AccessPermissions.List)
Dim locator As ILocator
locator = mediaCloud.Locators.CreateLocator(LocatorType.Sas, asset, accessPolicy)
gSasURL = locator.BaseUri
locator.Delete()
accessPolicy.Delete()
End Sub
Thanks.
The link above is certainly not SAS. If you read the documentation for Locator here: http://msdn.microsoft.com/en-us/library/windowsazure/hh974308.aspx#create_a_locator, you will notice that BaseUri is defined as
Part of the locator that provides the store/service/container
information about the asset. (for example, Dns Host name
http://someservice.cloudapp.net)
There's another property called ContentAccessComponent which gets returned as a part of locator and that contains the SAS. So in your code this is what you would do:
uploadSasUrl = locator.BaseUri & 'File Name' & locator.ContentAccessComponent
Basically you will concatenate BaseUri, file which is being uploaded and ContentAccessComponent. Do give it a try.
Also I noticed that you're deleting the access policy once you get the locator. I think you would need to keep the access policy in place till the time blob is uploaded.
all!
I'm solving two problems:
Stop using CAPICOM to sign/verify documents - because it's no longer supported by Microsoft (see more: Alternatives to Using CAPICOM)
Flowing out first we want to wide list of supported browsers by our system (customized Documentum webtop). Now it fully supported only by IE 6+ because of CAPICOM used as ActiveX.
For signing we use windows module CryptoPro because of only it officially have legal effect in Russia. Our system deployed in government of one Russian region.
Our system works already 5 years and there are many generated signs (all by CAPICOM). Signs is detached and persist in database.
We want to find solution to verify those signs in java code (wrapped in Applet).
I have tried code below, but I can't find any suitable method to verify any signature. This method always returns false.
public boolean verifyFile(String fileInput, String metadata, String base64Signature) throws Exception {
Security.addProvider(new BouncyCastleProvider());
byte[] signedContent = Base64.decode(base64Signature.getBytes("UTF-8"));
CMSSignedData cms7 = new CMSSignedData(signedContent);
CertStore certs = cms7.getCertificatesAndCRLs("Collection", "BC");
SignerInformationStore signers = cms7.getSignerInfos();
Collection c = signers.getSigners();
SignerInformation signer = (SignerInformation)c.iterator().next();
Collection certCollection = certs.getCertificates(signer.getSID());
Iterator certIt = certCollection.iterator();
X509Certificate cert = (X509Certificate)certIt.next();
Signature signature = Signature.getInstance("SHA1withRSA", "BC");
signature.initVerify(cert.getPublicKey());
String signedContentString = getSignedDataString(fileInput, metadata);
signature.update(signedContentString.getBytes("UTF-8"));
return signature.verify(signer.getSignature());
}
Have somebody any solution or already encountered this pr
I have an Excel VBA macro which does the equivalent of the following HTTP POST which works successfully:
Set WebClient = CreateObject("WinHttp.WinHttpRequest.5.1")
' ... Configure WebClient for a POST request
RequestBody = "<request>"
WebClient.send RequestBody
Previously, I had explicitly set the type of RequestBody as a String as in the following:
Set WebClient = CreateObject("WinHttp.WinHttpRequest.5.1")
' ... Configure WebClient for a POST request
Dim RequestBody As String
RequestBody = "<request>"
WebClient.send RequestBody
This appeared to work correctly except that the server received no request content.
On debugging through both versions a watch on RequestBody described its type as 'Variant/String' and the content was correct.
Why does the addition of a type cause this issue?
Hmm...
Try to add the reference to WinHTTP library (Tools - References). For no obvious reason sometimes it matters.
But Send method is declared as using a Variant parameter anyway, so making it String doesn't make sense.