How to configure docusign demo to live after promoting integration key - docusignapi

I used embedded signing and after successfully running on demo, promoted integration key and passed review.
What changes I need to in my code? Where I need to put promoted integration key? I know live have no token key integration like demo which is for 8 hours only.
I changed https://demo.docusign.net/restapi to https://www.docusign.net/restapi
$dsConfig = array(
'ds_client_id' => isset($session->data['user_id']) ? $session->data['user_id'] : "1",
'ds_client_secret' => 'eyJ0eXAiOiJNVCIsImFsZxxxxxxxxxxxxxx',
'signer_email' => $customer->isLogged() ? $customer->getEmail() : 'user#example.com',
'signer_name' => $customer->isLogged() ? $customer->getFirstName() . ' ' . $customer->getLastName() : 'John Doe',
'app_url' => HTTPS_SERVER . 'public/agreement-accept.html',
'authorization_server' => 'https://demo.docusign.net/restapi',
'session_secret' => isset($session->data['token']) ? $session->data['token'] : md5(time()),
'allow_silent_authentication' => true,
'accountId' => 'xxxxxxx',
'templateId' => 'xxxxx-xxxx-xxx-xxx-xxxx'
);
$config = new Configuration();
$config->setHost($dsConfig['authorization_server']);
$config->addDefaultHeader(
"Authorization",
"Bearer " . $dsConfig['ds_client_secret']
);
$apiClient = new ApiClient($config);

https://docusign.net/restapi is not a valid API endpoint.
In order to make API calls using your integration key, you'll need to implement one of the Authentication Workflows as documented here: https://developers.docusign.com/esign-rest-api/guides/authentication/
Once you have a valid token, you'll need to make a User Info call to determine the base URI for your account: https://developers.docusign.com/esign-rest-api/guides/authentication/user-info-endpoints

I did it by creating a generateRefreshToken() function in ApiClient Class:-
public function generateRefreshToken($client_id = null, $client_secret = null, $refresh_token = null)
{
if (!$client_id) {
throw new \InvalidArgumentException('Missing the required parameter $client_id when calling generateAccessToken');
}
if (!$client_secret || !$refresh_token) {
throw new \InvalidArgumentException('Missing the required parameter $client_secret when calling generateAccessToken');
}
if (!$refresh_token) {
throw new \InvalidArgumentException('Missing the required parameter $refresh_token when calling generateAccessToken');
}
$resourcePath = "/oauth/token";
$queryParams = array();
$integrator_and_secret_key = "Basic " . utf8_decode(base64_encode("{$client_id}:{$client_secret}"));
$headers = array(
"Authorization" => $integrator_and_secret_key,
"Content-Type" => "application/x-www-form-urlencoded",
);
$postData = array(
"grant_type" => "refresh_token",
"refresh_token" => $refresh_token
);
list($response, $statusCode, $httpHeader) = $this->callApi($resourcePath, self::$POST, $queryParams, $postData, $headers, null, null, true);
if(isset($response->access_token))
$this->config->addDefaultHeader("Authorization", "{$response->token_type} {$response->access_token}");
return array($this->getSerializer()->deserialize($response, '\DocuSign\eSign\Client\Auth\OAuthToken', $httpHeader), $statusCode, $httpHeader);
}
protected static function requestNewToken($refresh_token) {
$config = new Configuration();
$apiClient = new ApiClient($config);
$token = $apiClient->generateRefreshToken('clientid', 'secret_key', $refresh_token);
return array($token[0]['access_token'],$token[0]['refresh_token'],time() + 86400 * 27);
}
protected static function getToken() {
$tokenFile = __DIR__ . '/token.json';
$access_token = null;
if (file_exists($tokenFile)) {
$data = json_decode(file_get_contents($tokenFile), true);
$access_token = $data['access_token']; // todo consider field names
$refresh_token = $data['refresh_token']; // todo consider field names
$expires_in = $data['expires_in']; // todo consider field names
if ($expires_in <= time()) {
$access_token = null;
}
}
if (!$access_token) {
list($access_token,$refresh_newtoken,$expires_in) = self::requestNewToken($refresh_token);
if (!$access_token || !$refresh_newtoken || !$expires_in) {
throw new Exception('Could not request new token.');
}
file_put_contents($tokenFile, json_encode(array(
'access_token' => $access_token,
'refresh_token' => $refresh_newtoken,
'expires_in' => $expires_in
)));
}
return $access_token;
}
Also https://www.docusign.net/restapi is a valid API endpoint for production.It works for me. https:// and www should be there...
$dsConfig = array(
'ds_client_id' => isset($session->data['user_id']) ? $session->data['user_id'] : "1",
// The app's DocuSign integration key's secret
'ds_client_secret' => $token,
'signer_email' => $customer->isLogged() ? $customer->getEmail() : 'user#example.com',
'signer_name' => $customer->isLogged() ? $customer->getFirstName() . ' ' . $customer->getLastName() : 'John Doe',
// return url
'app_url' => HTTPS_SERVER . 'public/agreement-accept.html',
'authorization_server' => 'https://www.docusign.net/restapi',
'session_secret' => isset($session->data['token']) ? $session->data['token'] : md5(time()),
'allow_silent_authentication' => true,
'accountId' => 'xxx',
'templateId' => 'xxxx'
);

Related

Stripe symfony subscription user

I'm new to stripe, I managed to make the payment via the doc but I can't link my user to the subscription, for example I would like that when the payment is made, in my user entity I would like whether the user is put in premium or when the subscription is cancelled, whether the user is not in premium.
In my user entity I put a "premium" boolean field
Can you help me please?
#[Route('/abonnement/panier/2/checkout', name: 'aboCheck')]
public function stripe2(Request $request): Response
{
if (!$this->getUser()) {
return $this->redirectToRoute('public');
}
\Stripe\Stripe::setApiKey('sk_test....');
$priceId = 'price.....';
if (!$priceId) {
throw $this->createNotFoundException('Bad plan id!');
}
$username = $this->getUser()->getUsername();
$email = $this->getUser()->getEmail();
$session = \Stripe\Checkout\Session::create([
'success_url' => 'http://127.0.0.1:8000/abonnement/panier/2/order/success?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => 'http://127.0.0.1:8000/abonnement/panier/2',
'mode' => 'subscription',
'line_items' => [[
'price' => $priceId,
// For metered billing, do not pass quantity
'quantity' => 1,
]],
'client_reference_id' => $username,
'customer_email' => $email,
'metadata' => [
'username' => $username
]
]);
return $this->redirect($session->url);
}
#[Route('/webhook', name: 'webhook')]
public function handle(ManagerRegistry $doctrine)
{
\Stripe\Stripe::setApiKey('sk....');
$endpoint_secret = 'whsec.....';
$payload = file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;
try {
$event = \Stripe\Webhook::constructEvent(
$payload,
$sig_header,
$endpoint_secret
);
} catch (\UnexpectedValueException $e) {
// Invalid payload
http_response_code(400);
exit();
} catch (\Stripe\Exception\SignatureVerificationException $e) {
// Invalid signature
http_response_code(400);
exit();
}
$user = $this->getUser();
// Handle the event
switch ($event->type) {
case 'customer.subscription.trial_will_end':
$subscription = $event->data->object;
print_r($subscription); // contains a \Stripe\Subscription
// Then define and call a method to handle the trial ending.
// handleTrialWillEnd($subscription);
break;
case 'customer.subscription.created':
$subscription = $event->data->object;
print_r($subscription); // contains a \Stripe\Subscription
// Then define and call a method to handle the subscription being created.
// handleSubscriptionCreated($subscription);
break;
case 'customer.subscription.deleted':
$subscription = $event->data->object;
print_r($subscription); // contains a \Stripe\Subscription
// Then define and call a method to handle the subscription being deleted.
// handleSubscriptionDeleted($subscription);
break;
case 'customer.subscription.updated':
$subscription = $event->data->object;
print_r($subscription); // contains a \Stripe\Subscription
// Then define and call a method to handle the subscription being updated.
// handleSubscriptionUpdated($subscription);
break;
default:
// Unexpected event type
error_log('Received unknown event type');
}
return new Response(Response::HTTP_OK);
}
#[Route('/abonnement/panier/2/order/success', name: 'success')]
public function successStripe(ManagerRegistry $doctrine, Request $request): Response
{
if (!$this->getUser()) {
return $this->redirectToRoute('public');
}
$priceId = 'price......';
\Stripe\Stripe::setApiKey('sk......');
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
$myuser = $this->getUser();
$session = \Stripe\Checkout\Session::retrieve($request->get('session_id'));
$customer = \Stripe\Customer::retrieve($session->customer);
if (($session->status == 'complete') & ($customer->email == $myuser->getEmail())) {
$entityManager = $doctrine->getManager();
$myuser->setProfileId($customer->id);
$myuser->setPremium(true);
$entityManager->flush();
} else {
return $this->redirectToRoute('aboStripe');
}
return $this->render('stripe/success.html.twig', [
'customer' => $customer
]);
}
#[Route('/customer-portal', name: 'customer-portal')]
public function portal(): Response
{
// Set your secret key. Remember to switch to your live secret key in production.
// See your keys here: https://dashboard.stripe.com/apikeys
\Stripe\Stripe::setApiKey('sk_test.....');
// This is the URL to which the user will be redirected after they have
// finished managing their billing in the portal.
$myuser = $this->getUser();
$stripe_customer_id = $myuser->getProfileId();
$session = \Stripe\BillingPortal\Session::create([
'customer' => $stripe_customer_id,
'return_url' => 'http://127.0.0.1:8000/abonnement/panier/2',
]);
return $this->redirect($session->url);
}

How can axios-mock-adapter return an object on GET request?

There's a block of code that uses axios-mock-adapter and returns an object via a GET request:
mock.onGet('/api/auth').reply((config) => {
const data = JSON.parse(config.data);
const {email, password} = data;
const user = _.cloneDeep(authDB.users.find(_user => _user.data.email === email));
const error = {
email : user ? null : 'Check your username/email',
password: user && user.password === password ? null : 'Check your password'
};
if ( !error.email && !error.password && !error.displayName )
{
delete user['password'];
const access_token = jwt.sign({id: user.uuid}, jwtConfig.secret, {expiresIn: jwtConfig.expiresIn});
const response = {
"user" : user,
"access_token": access_token
};
return [200, response];
}
else
{
return [200, {error}];
}
});
User is a JSON object with various amounts of values. How is this possible? What would it look like in the URL? I'm studying the code block to learn how to do it without axios-mock-adapter.

How do you get md:NameIDFormat to appear in the SAML2 Metadata output?

I have my SAML2 "working" (authentication: success) but shibboleth isn't sending me any claim data, I need just the users email :)
The shibboleth people are telling me to add this to my SAML2 metadata... it's very clearly not there.
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-
format:emailAddress</md:NameIDFormat>
We're using the OWIN middleware from https://github.com/Sustainsys/Saml2/ to get this all to work, but it's pretty stock config?
additionalProviders["saml2p"] =
(IAppBuilder app, string signInAsType, AuthenticationProviderElement config) =>
{
var opt = new Saml2AuthenticationOptions(false)
{
SPOptions = new SPOptions
{
EntityId = new EntityId("https://my.site.ca")
},
SignInAsAuthenticationType = signInAsType,
AuthenticationType = "saml2p",
Caption = "MySite",
Notifications = new Saml2Notifications()
{
AcsCommandResultCreated = (result, response) =>
{
var claimsIdentity = result.Principal.Identity as ClaimsIdentity;
//None of this exists in the result
var userEmail = claimsIdentity.Claims.FirstOrDefault(x => x.Type == "User.email");
var userFirstName = claimsIdentity.Claims.FirstOrDefault(x => x.Type == "User.FirstName");
var userLastName = claimsIdentity.Claims.FirstOrDefault(x => x.Type == "User.LastName");
},
LogoutCommandResultCreated = commandResult =>
{
// Post logout URL
commandResult.Location = new Uri("/login", UriKind.Relative);
}
},
};
Sustainsys.Saml2.Configuration.Options.GlobalEnableSha256XmlSignatures();
opt.IdentityProviders.Add(new IdentityProvider(
new EntityId("https://their.site.ca/shibboleth-idp/shibboleth"),
opt.SPOptions)
{
LoadMetadata = true
});
app.UseSaml2Authentication(opt);
};
return additionalProviders;
TL;DR; md:NameIDFormat not in SustainSys SAML2 metadata output
The config on my end was correct, the problem was the config in shibboleth not sending the http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier claim back.

IdentityServer 4 - user roles missing

In my Client I have the following set up.
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
//options.DefaultSignInScheme = "Cookies",
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = "...";
options.ClientId = "...";
options.SaveTokens = true;
options.ClientSecret = "secret";
options.SignInScheme = "Cookies";
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("roles");
options.ResponseType = "code id_token";
options.GetClaimsFromUserInfoEndpoint = true;
options.Events = new OpenIdConnectEvents()
{
OnTokenValidated = tokenValidatedContext =>
{
var identity = tokenValidatedContext.Principal.Identity
as ClaimsIdentity;
var targetClaims = identity.Claims.Where(z =>
new[] {"sub"}.Contains(z.Type));
var newClaimsIdentity = new ClaimsIdentity(
targetClaims,
identity.AuthenticationType,
"given_name",
"role");
tokenValidatedContext.Principal =
new ClaimsPrincipal(newClaimsIdentity);
return Task.CompletedTask;
},
OnUserInformationReceived = userInformationReceivedContext =>
{
return Task.FromResult(0);
}
};
});
My client at the level of IdentityServer is defined as follows.
new Client()
{
ClientName = "My App",
ClientId = "mymagicapp",
AllowedGrantTypes = GrantTypes.Hybrid,
RedirectUris = new List<string>()
{
"https://..."
},
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"roles"
},
ClientSecrets = { new Secret("secret".Sha256()) },
PostLogoutRedirectUris =
{
"https://..."
}
}
The new "roles" scope is added as per below.
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>()
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResource("roles", "Your role(s)", new List<string>(){"role"})
};
}
A user is defined as follows.
new TestUser()
{
SubjectId = "abcdef",
Username = "Jane",
Password = "password",
Claims = new List<Claim>()
{
new Claim("given_name", "Jane"),
new Claim("family_name", "Doe"),
new Claim("role", "FreeUser")
}
}
After logging in to my MVC client, in the Controller the User.Claims object does not contain role claim.
However, in the OnUserInformationReceived the userInformationReceivedContext's User object does contain the role claim.
What am I missing?
Based on
Missing Claims in the ASP.NET Core 2 OpenID Connect Handler?
OIDC, I cannot add extra claims from userinfo endpoint
the solution was to add options.ClaimActions.MapJsonKey("role", "role"); inside .AddOpenIdConnect(options => ...)
From the second link:
2.0 no longer adds all possible information from the user-info endpoint, it was causing major cookie bloat leading to login issues. There is now a system called ClaimActions where you can select which elements you want to map from the user info doc to claims. See OpenIdConnectOptions.ClaimActions.

Xamarin.Auth with Twitter

I am trying to implement login with Facebook and Twitter. I got it working with Facebook but don't know how to do it with Twitter. Are there any examples? My Facebook implementation is like this:
var auth = new OAuth2Authenticator(
clientId: "*****************",
scope: "email",
authorizeUrl: new System.Uri("https://m.facebook.com/dialog/oauth/"),
redirectUrl: new System.Uri("http://www.facebook.com/connect/login_success.html"));
StartActivity(auth.GetUI(this));
auth.Completed += (senderFb, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
AccountStore.Create(this).Save(eventArgs.Account, "Facebook");
// Now that we're logged in, make a OAuth2 request to get the user's info.
var request = new OAuth2Request("GET", new System.Uri("https://graph.facebook.com/me"), null, eventArgs.Account);
request.GetResponseAsync().ContinueWith(t =>
{
if (!t.IsFaulted && !t.IsCanceled)
{
var obj = JsonValue.Parse(t.Result.GetResponseText());
if (obj != null)
{
var user = new UserProfile
{
FirstName = obj["first_name"],
LastName = obj["last_name"],
FacebookProfileLink = obj["link"],
FacebookToken = eventArgs.Account.Properties["access_token"],
Gender = obj["gender"] == "female" ? "Female" : "Male",
EmailAddress = obj["email"],
DisplayName = obj["name"],
Name = obj["name"],
LoginName = obj["email"]
};
SignUpUser(user);
}
}
}, uiScheduler);
}
};
You can use oauth1 like this.
this.Authenticator = new OAuth1Authenticator (ConsumerKey, ConsumerSecret, RequestTokenUrl, AuthorizeUrl, AccessTokenUrl, DummyCallBackUrl, (IDictionary<string, string> accountProperties) => {
string screen_name = "";
if (accountProperties.TryGetValue("screen_name", out screen_name)) {
Account a = new Account(screen_name, accountProperties);
AuthenticatorCompletedEventArgs e = new AuthenticatorCompletedEventArgs(a);
CompleteAuthentication(e);
}
return null;
});
twitter api dosen't fully support OAuth2

Resources