"errorCode":"PARTNER_AUTHENTICATION_FAILED" when deployed in test server - docusignapi

I have successfully implemented and integrated Docusign in my application with the JWT grant which is perfectly working in the local server. Same application I deployed in the test environment server then I am getting below error.
Error while requesting server, received a non successful HTTP code 401 with response Body: '{"errorCode":"PARTNER_AUTHENTICATION_FAILED","message":"The specified Integrator Key was not found or is disabled. An Integrator key was not specified."}'
For the test server also should I need to make an app to go live in DocuSign or is there any option to test?
My requirement is like need endpoint developed in java Spring boot which will filter based on signer email and return remaining envelopes and this envelope list with be displayed in the mobile application. So for this, I have to deploy my spring boot application into the test server.
protected ApiClient createDocuSignApiClient() {
ApiClient apiClient = new ApiClient(this.docusignConfig.getBaseUrl());
try {
val privateKeyBytes =
FileCopyUtils.copyToByteArray(
new FileSystemResource(this.docusignConfig.getPrivateKey()).getInputStream());
List<String> scopes = new ArrayList<>();
scopes.add(OAuth.Scope_SIGNATURE);
val accessToken =
apiClient.requestJWTUserToken(
this.docusignConfig.getIntegrationKey(),
this.docusignConfig.getUserId(),
scopes,
privateKeyBytes,
3600);
apiClient.setAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
apiClient.setBasePath(this.docusignConfig.getBaseUrl());
Configuration.setDefaultApiClient(apiClient);
} catch (ApiException | IOException exception) {
LOG.error(exception.getMessage());
}
return apiClient;
}
#Docusign API
docusign.integration-key=xxxxxxxfc-7a73c309eccb
docusign.private-key=src/main/resources/private.key
docusign.user-id=dxxxxxxx-0c9253822c79
docusign.base-url=https://demo.docusign.net/restapi
docusign.account-id=x5e-d39f7ffaeec3xxxxxxxxxx
docusign.return-url=https://www.sample.com
These properties are set in application properties files
by configuration properties #ConfigurationProperties appending values

The terms BasePath, BaseUri, and BaseUrl are confusing and are used inconsistently.
When you call apiClient.setOAuthBasePath() this is a path, not a URL and it's the base path for the OAuth server, not the APIs.
So the value you need to pass is "account-d.docusign.com" (or for production "account.docusign.com") and that is your issue here.

Related

The SSL connection could not be established, see inner exception. - DocuSign EnvelopesApi calls ONLY to PROD environment

I have migrating our Apis to use Docusign OAuth authentication flow. While testing I found that the code works perfectly fine when I point to Docusign Demo environment. However when I point to docusign Prod environment I get the following error.
The SSL connection could not be established, see inner exception.
There inner exception is actually null.
The docusign Auth call is fine and we get the accountId as expected. However the EnvelopesApi calls are failing. I do have a ticket open with Docusign but wanted to see if any one can help.
Our Api is deployed as a Windows Service and is in dotnet core 5.0. However I have tested this by deploying the Api to an IIS website with ssl binding and I can repro the same exception.
Auth Flow - OAuth JwtFlow
API BasePath as - "https : //docusign.net/restapi" (space added on purpose)
OAuth Base Path as - "account.docusign.com"
Below code get the accountId and sets the AccessToken. This is successful.
var privateKeyBytes = Encoding.UTF8.GetBytes(docuSignKey);
try
{
_tokenInfo = apiClient.RequestJWTUserToken(docusignConfig.IntegratorKey, docusignConfig.UserIdGuid,
docusignConfig.OAuthBasePath, privateKeyBytes, docusignConfig.TokenExpiryInHours);
var userInfo = apiClient.GetUserInfo(_tokenInfo?.access_token);
var account = userInfo?.Accounts
.FirstOrDefault(la => la.IsDefault.ToLowerInvariant() == true.ToString().ToLowerInvariant())
?? userInfo?.Accounts.First();
SetApiClientConfiguration(docusignConfig);
return account?.AccountId;
}
catch (Exception ex)
{
ESignLogger.Error($"{GetType().Name}.{nameof(AuthorizeAndGetAccountId)}. Error in getting account details. " + ex.Message);
return null;
}
Below code is the envelopesApi call which fails.
var recipientResponse = await _envelopesApi.ListRecipientsAsync(accountId, envelopeId);
The URLs for eSignature REST API calls for the DocuSign production environments can be different for different customers based on where their account is provisioned.
The default URL (https://www.docusign.net/restapi) can be used in some cases.
However, the best practice is to call the User Info endpoint for the particular user (it's by account, but a user can be a member of more than one account) and for each account that user is a member of, you'll get back a baseURI that can be different than the default I just posted above.
If this wasn't your issue, it may also be that you need to download one of the certificates to your server. You can find all of DocuSign SSL certificates in this page.
Steps to check:
OAuth step to obtain an access_token. You're using the JWT grant flow. If it returns an access token from account.docusign.com then you've succeeded. Note that your client ID (integration key) needs to pass go-live before it can be used with account.docusign.com
Next use the access token with the right base url for the eSig API. You can determine the right base url by using the /oauth/userinfo API. Or if your application is just for your own company, you can just look up your DocuSign account's base URL from the API & Keys page of the eSignature Settings (admin) tool.

Service to service authentication in Azure without ADAL

I configured azure application proxy for our on-premise hosted web service and turned on Azure AD authentication. I am able to authenticate using ADAL but must find a way to get the token and call web service without ADAL now (we are going to use this from Dynamics 365 online and in sandbox mode I can't use ADAL). I followed some examples regarding service to service scenario and I successfully retrieve the token using client credentials grant flow. But when I try to call the app proxy with Authorization header and access token, I receive an error "This corporate app can't be accessed right now. Please try again later". Status code is 500 Internal server error.
Please note the following:
I don't see any error in app proxy connectors event log.
I added tracing on our on-premise server and it seems like the call never comes there.
If I generate token with ADAL for a NATIVE app (can't have client_secret so I can't use client credentials grant flow), I can call the service.
I created an appRole in manifest for service being called and added application permission to the client app.
This is the way I get the token:
public async static System.Threading.Tasks.Task<AzureAccessToken> CreateOAuthAuthorizationToken(string clientId, string clientSecret, string resourceId, string tenantId)
{
AzureAccessToken token = null;
string oauthUrl = string.Format("https://login.microsoftonline.com/{0}/oauth2/token", tenantId);
string reqBody = string.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&resource={2}", Uri.EscapeDataString(clientId), Uri.EscapeDataString(clientSecret), Uri.EscapeDataString(resourceId));
HttpClient client = new HttpClient();
HttpContent content = new StringContent(reqBody);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
using (HttpResponseMessage response = await client.PostAsync(oauthUrl, content))
{
if (response.IsSuccessStatusCode)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(AzureAccessToken));
Stream json = await response.Content.ReadAsStreamAsync();
token = (AzureAccessToken)serializer.ReadObject(json);
}
}
return token;
}
AzureAccessToken is my simple class marked for serialization.
I assume it must be something I haven't configured properly. Am I missing some permissions that are required for this scenario?
Any help is appriciated.

Azure. Owin OpenId authentication. Added custom claims. AuthorizationCodeReceived is not called

I've almost configured my OpenId owin authentication/authorization in Azure Active Directory. My configuration is the following:
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
CookieName = "AppServiceAuthSession"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = ClientId,
Authority = _authority,
PostLogoutRedirectUri = PostLogoutRedirectUri,
RedirectUri = PostLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
},
AuthorizationCodeReceived = async context =>
{
var id = new ClaimsIdentity(context.AuthenticationTicket.Identity.AuthenticationType);
id.AddClaims(context.AuthenticationTicket.Identity.Claims);
var appToken = "MyToken";
id.AddClaim(new Claim("MyTokenKey", appToken));
context.AuthenticationTicket = new AuthenticationTicket
(
new ClaimsIdentity(id.Claims, context.AuthenticationTicket.Identity.AuthenticationType),
context.AuthenticationTicket.Properties
);
}
},
});
But I want to add one more application token (not user token) to claims list to be able to have ability to use this token in any place on my site. Also it's good point for me that I don't need to get this token from my external token provider more then one time per an authentication session.
But place, where I'm going to add my logic (AuthorizationCodeReceived as well as other methods from OpenIdConnectAuthenticationNotifications) is called only when I use my local IIS(run locally), when I try to use azure IIS, this method has not been called at all. In this case my User is authenticated anyway, but this method and the similar methods from OpenIdConnectAuthenticationNotifications(except RedirectToIdentityProvider) are not fired.
I've downloaded the git source code of Katana project and referenced this project to my instead of the official nuget packages to debug its and as I think currently, I've found the reason why it happens. The AuthorizationCodeReceived "event" method is called from OpenIdConnectAuthenticationHandler class in AuthenticateCoreAsync method. But also, the calling of this method is required that the below checking must give the true result:
if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase)
&& !string.IsNullOrWhiteSpace(Request.ContentType) // May have media/type; charset=utf-8, allow partial match.
&& Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase)
&& Request.Body.CanRead)
{
//some necessary preparation to call `AuthorizationCodeReceived` event method
}
As we can see, this checking allows only POST requests and I see these POST requests when I run app in local IIS, but I cannot see these POST requests when I deploy my application in azure portal (I've debugged both of options : on local IIS and in azure portal).
As summary from the above, this is the only one difference between these runnings. (Azure IIS doesn't send POST request at all by some reason).Any other methods in Katana project (which I checked) are called in the same way.
Could anybody help with it?
PS Note, I check any changes only after clearing of browser data (cache/history and so on).
The answer is the following:
The authorization in azure portal should be configured as shown above. In case if you chose LogIn with Azure Active Directory, then app services auth takes place outside of your app, and the custom authorization is not triggered.

Custom authorization with Azure AD Authentication in OWIN Web API

We are using Azure AD authentication for one of our client application. We want to implement claims based authorization along with it.
Our application set up is Angular Based client app connecting with Web API (both client server secured using Azure AD Bearer Authentication). Server application is hosted using OWIN.
We need to provide custom authorization on server side. There is a provision in Azure AD for adding users and roles. However, that is not enough for us. Our user management is through AD & Security Groups. To gain access to application, users need to part of a base group and further rights (access particular section of application, edit a specific entity etc.) are assigned based on additional groups or given directly to users in the application. Essentially, not all users will be registered in the application and we may have to query the AD using graph API to check which all application specific groups they belong.
OWIN authentication and authorization model is based on Authentication Server and Resource server. We can separate them on need basis. However, in our case, we need to split the authentication and authorization. When the client presents the bearer token, we need to verify if the token is valid and then add claims to user profile. We also need to cache the user claims so that we do not hit the database frequently. (Our client app make multiple Web API calls in one user action.)
What is the location in Identity 2.0 where
I can verify the token &
insert application specific claims
If my entire application revolves around the user authorization and all queries need to be filtered on what data the user can access, which is a more suitable design pattern for the Web API application?
I believe what you're looking for are the Authentication and Authorization filters in the ASP.NET Web API 2.0 stack.
You can implement per-web method authorization by implementing System.Web.Http.Filters.IAuthorizationFilter on an attribute class, then decorate the web action methods of your service controller with that attribute. Web API 2.0 will select a method based on URL routing, notice that there is an attribute on that method implementing IAuthorizationFilter, and will call the ExecuteAuthorizationFilterAsync method on that attribute instance before calling the web method. Placing the authorization step before the web method invocation allows invalid requests to be discarded quickly, before getting into the heavy lifting of parameter binding.
The incoming token is validated by an IAuthenticationFilter implementation which executes before the authorization step.
Documentation and examples are extremely hard to find. Here's one of the few search results that are actually relevant: http://thegrumpycoder.com/post/105427070626/secure-web-services-with-web-api-and-sitecore
you can check if this helps...
UserProfile profile = new UserProfile(); //To deserialize the response stream (JSON)
string tenantId = ClaimsPrincipal.Current.FindFirst(TenantIdClaimType).Value;
AuthenticationResult result = null;
try
{
// Get the access token from the cache
string userObjectID =
ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")
.Value;
AuthenticationContext authContext = new AuthenticationContext(Startup.Authority, new NaiveSessionCache(userObjectID));
//use ClientID, ClientSecret
ClientCredential credential = new ClientCredential("b557ceed-xxxx-xxxx-xxxx-xxxxxxxbc240", "AXFxx//xxxxxxxxxxxxxjVFz4sqYm8NDAPEOLkU=");
result = authContext.AcquireTokenSilent("https://graph.windows.net", credential,
new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
// AcquireTokenSilent may throw exception if the cache is empty. In that case, logout the user and make him login.
string requestUrl = String.Format(
CultureInfo.InvariantCulture,
"https://graph.windows.net/cdmsdev.onmicrosoft.com/groups/b40xxxx-14a8-xxxx-9559-xxxxxxca90c8/members/?api-version=1.6");
//Above grap API url is for getting list of users who belong to a specific group (with GUID b40xxxx-1....)
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
var upn = ClaimsPrincipal.Current.Identity.Name;
string responseString = response.Content.ReadAsStringAsync().Result;
profile = JsonConvert.DeserializeObject<UserProfile>(responseString);
if (profile.Users.Contains(upn)) //check if the current user is in the list of users of the Admin group
return true;
}
}
catch (Exception e)
{
//handle authorization exception here
}
The graph API URL can be replaced with a function to check for membership of a specific group which will directly return a bool value instead of getting all users of that group.

Securely calling a WebSite hosted Web API from an Azure WebJob

I have a continuously scheduled web job that's monitoring a message queue, pulling messages off and calling a Web API on the peer Web Site to process the messages (in this case using SignalR to send notifications to appropriate users).
What would be the best way in this case to call the web API securely? The API being hosted in the web site is obviously exposed otherwise. Perhaps something using Basic Auth or storing a security token in config and passing it from the job to the web API. Or creating a custom AuthorizeAttribute?
Ant thoughts on securing the Web API call from the WebJob would be much appreciated. The API should only be callable from the WebJob.
UPDATE:
Something like this perhaps?
First I declare this class;
public class TokenAuthenticationHeaderValue : AuthenticationHeaderValue
{
public TokenAuthenticationHeaderValue(string token)
: base("Token", Convert.ToBase64String(Encoding.UTF8.GetBytes(token)))
{ }
}
Then the caller (the WebJob) uses this class to set an auth header when making the HTTP request;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(/* something */);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new TokenAuthenticationHeaderValue("TOKEN FROM CONFIG");
// ....
Over in the Web API we check the request looking for the expected token in the auth header, currently the code is pretty ugly but this could be put into a custom attribute;
public HttpResponseMessage Post([FromBody]TheThing message)
{
var authenticationHeader = Request.Headers.Authorization;
var token = Encoding.UTF8.GetString(Convert.FromBase64String(authenticationHeader.Parameter));
if (authenticationHeader.Scheme != "Token" || token != "TOKEN FROM CONFIG")
{
return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "No, no, no. That's naughty!");
}
// All OK, carry on.
So this way the WebJob calls the Web API on the peer web site and security is achieved by passing a token that is securely held in the Azure configuration, both the Site and Job have access to this token.
Any better ideas?
Sounds like Basic Authentication would be fine for your scenario.
Great tutorial here: Basic Authentication

Resources