I have implemented JWT in order to authenticate on Google cloud, as described in https://developers.google.com/identity/protocols/oauth2/service-account#jwt-auth
To my surprise, I've noticed that I could change some chars on the private key, and it would still authenticate. Changing chars in some places didn't work, and I got OpenSSL unable to sign data from the PHP JWT library. And some other places resulted in access being denied. But for example, when I changed a char in this line - it authenticated well.
How can that be? That is, I don't think it's possible to change any char on the private key and get it to work. But that's what I see on my local and when checked via GitPod. So I'm wondering what I might be missing.
Here's an example PHP code:
<?php
include_once __DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
use Symfony\Component\HttpClient\HttpClient;
$privateKey = <<<EOD
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhziG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCyGkIPaez6r8jO
8a4oXYtxlDhfnYYQXs/fgG3I7wbbguw5lwcYEQPkm6fcWFpeqeMeOk2tuQKrJBOl
1hRqKEY4QGv1lHR0zatiQ1WOo9n+IgekmNwWLIMH176hRbhA/2uHHBjFgzFsLHOy
JtTrOM/WXyCooVLRy45D1vci7epbkYIxiWmFXcHKkeCldprqHy1oHc/nOYPdbPfZ
0lF0g3y4cuzmiaukiDtaGm9ZfnsFXo+jqlubnF0VvLrr41LddMJMoqh9aOA/KTkt
7L74JQJjGFVRwK/4/8l6xAuwua4IhdZMoV3XWijCeQt8Exi7YohaYRUYlwA5Koz4
96caSsdzAgMBAAECggEAGrkw51IsAjNlDJQb3yemGC02xjYDGyq2wyDomCkxXLeI
zV1ZbaWD8YXfioLhUGnqT6tM43+qpFY98nisSH9xhdg4urkDPlFr4UscJ9JzD5w4
jFx5TYRxRrh6/ITTEEGi9ztihiRYwpPq6jTEZuT33oEYi+Tk4eDKoGg9XcrYCtQK
4WmVt/5wUxE+G0AZEz+Z0fe1xFCfNRZ/4tpso1xopMiUwgNjNaFHAquvJfxbozKP
um5lS8wkETXbH+EnjmSYevPibuLfoZzqfTYxVSwaSqJ8epSk4N3sad7SCq5RvLAv
kQ+BvI582HCAiYPU9K+RTyPbedJuBz8ubgJZpHc5zQKBgQDXzZBSSYXaKLFOHc5j
BvNNmddWZFHFmC8XzccTI3arof8DRrB3w9NUEYwripttJ0cMtozjbxotCNiEybKG
hwaRyBg7MGPVkBsCKDG8UrVA7YoW2eWtcVOeKoSllSjhVsh+wjqi2+g1T6mSrue2
RviFC8k6w2+mYAQYhSwVLpHlXQKBgQDTRvj/CJr9wrd5WxHJ3Gk/D3ZYFW/9H2+M
Ncsi4gQ3fRIhPhAgoCTepEQ6/cyO3KRNY3xrqOXmPII2epfNHg0P3tq0P3zBkbbv
Y1Q9+uFJ3ktFHjTC5BIH4yX6vuPf3iRFiDZq5tIfAR0ACCN/SU1WUoHCrTOJ3MNu
mlSX2SNDDwKBgQDGCBFkMavvImByes+l9/7VO1NsJ+sSFDFC+sawPWHoZWQKsZfG
j6EiCGhEnJE8fUqp0+s92fp/URq/4Ac/hDD3HlN+HU2/8NmYBSJ+2rcRuel6RsKJ
gvFkt0e6W0KEZoreJ4Z/ZKWWJmBKBs8DaeUs0j/6+NVAK+QWTD7DwVSI0QKBgAtC
vCCzr7cYuriwHumYYs+mnlMhiV9/Xm2lrFcGntzqQJ4e9bMXdf+b17shLdbrcaJi
TA5c6Sv1S6dlr1OSZ3XSFewHejnC73Ig5CuNhJZwT6i2bG96wm9DLxIHPJQA/gPq
t6PI+6gFYitPQ70UBhg0u4/JtXaCmrP5a8rQGu4HAoGAVM5lBBRSBSmsbdt4+pWx
/nHVl2XlhhrFpxjPE0VVr0xIv9K8lt/yw3pItTs6zCLxqFYPRSmsLhPKqkxr0VIx
Mg7JhqzjI+AtBoPccRRZwj4DFtjZXW+u6/mrd00IfMFsUw90IhaPRi+eCowSBIE7
4riamH03XlC7Ce3McVRrHyM=
-----END PRIVATE KEY-----
EOD;
$payload = [
'iss' => "bar#foo.iam.gserviceaccount.com",
'sub'=> "bar#foo.iam.gserviceaccount.com",
'aud'=> "https://healthcare.googleapis.com/",
'iat' => time(),
'exp' => time() + 3600,
];
$jwt = JWT::encode($payload, $privateKey, 'RS256');
$client = HttpClient::create();
$url = 'https://healthcare.googleapis.com/v1/projects/foo/locations/us-central1/datasets/my-dataset/fhirStores/my-fhir-store/fhir/Patient';
$patientIdentifier = 'Some-name' . time();
$response = $client->request('POST', $url, [
'headers' => [
'Content-Type' => 'application/fhir+json',
'Authorization' => 'Bearer ' . $jwt,
],
'json' => [
'resourceType' => 'Patient',
'name' => [
0 => [
'family' => 'Migo',
'given' => [
0 => 'Dada',
],
],
],
'gender' => 'male',
'birthDate' => '1980-09-24',
],
]);
echo $response->getContent();
Here is a short video showing the problem I face. I've run it on GitPod, just to be sure it doesn't have my credentials anywhere on it. In the video you can see:
1st execution with the un-altered private key - works well
2nd execution with an altered private key - Still works (and obviously it shouldn't)
3rd execution, undo the previous change, and alter the private key elsewhere - now I get 401.
p.s. I've already changed the private key, so the one here is no longer valid :)
I understand, hashing, signing, private keys, etc very well. Your claim is impossible mathematically. Any change to the private key will result in a different hash which means the public key will no longer work to validate the signature. That form of weakness would have been discovered long ago. Private/public key validation cannot be manipulated by changing the values in one of the keys without changing the other.
One minor point is that the private key is base-64 encoded. You would need to replace those characters with valid base-64 data, which you might have done, but you did not explain in detail what you changed.
Perhaps edit your question with actual code to demonstrate. Give this some thought, if you can demonstrate this, you will be a millionaire next week or at least famous worldwide.
Related
Is there any way using AWS Cognito to send the user their verification code, have them enter the code, verify it is a valid code, THEN have them set their username and password?
For some reason, the workflow in my mind seems strange for the user to enter their code and new password in the same step. I want to check their code, and if it is valid, then take them to the screen to reset their password.
So far I've used the API function call:
forgotPassword
To send the code, which works fine, and from all my reading of the docs and searching here and online, I see that the next step is to call:
confirmForgotPassword
But in this step, it requires the new password (from what I can tell from the documentation):
$result = $client->confirmForgotPassword([
'AnalyticsMetadata' => [
'AnalyticsEndpointId' => '<string>',
],
'ClientId' => '<string>', // REQUIRED
'ClientMetadata' => ['<string>', ...],
'ConfirmationCode' => '<string>', // REQUIRED
'Password' => '<string>', // REQUIRED
'SecretHash' => '<string>',
'UserContextData' => [
'EncodedData' => '<string>',
],
'Username' => '<string>', // REQUIRED
]);
Am I missing something?
For context, I'm using the PHP API, but I'm really just looking for the correct API calls in the correct order to accomplish what I'd like if it is even possible.
Thanks in advance.
I changed my workflow so that I used a lambda function in AWS to send a link with the code, this way I validate the code on the link click and then the user can enter their password in.
Doesn't seem possible to do this in two steps.
I am using laravel 5.2 and I have to create keep me logged in functionality.
I have used below code to set cookie:
$response->withCookie(cookie('email', $request['email'], 60));
for this I have included below namespace:
use Cookie;
After setting cookie I printed response and get something like below:
Response {#1028
+original: ""
+exception: null
+headers: ResponseHeaderBag {#1029
#computedCacheControl: array:1 [
"no-cache" => true
]
#cookies: array:1 [
"" => array:1 [
"/" => array:1 [
"email" => Cookie {#989
#name: "email"
#value: "abc#gmail.com"
#domain: null
#expire: 90012626276.0
#path: "/"
#secure: false
#httpOnly: true
}
]
]
]
But When I try retrieving this cookie using any of below code it returned 'null'
$request->cookie('email');
OR
echo cookie::get('email');
Searching on web didn't helped much as I don't have much time therefore posted it over here.
Also It would be great if someone can explain that would it be fine if I use setcookie php function to set cookie?
My colleague asked me to use laravel specific functions. So I am trying to implement -->
$response->withCookie(cookie('email', $request['email'], 60));
Thanks!!
To set a cookie you should use the following code without calling cookie() function:
$response->withCookie('email', $request['email'], 60);
I am trying to use the built-in driver for Mailgun to send email. Here's what I have done so far.
Installed Guzzle driver.
Added the following to my config\services.php
'mailgun' => [
'domain' => env('sandbox54d5c9ed96434d689f971fd3.mailgun.org'),
'secret' => env('key-e800aa77cbda23ee8471dd5e'),
],
In my config\mail.php I have added
'driver' => env('MAIL_DRIVER', 'mailgun'),
However, now if I try to do forget password. It says we have sent an email but I don't get anything.
The domain is my sandbox domain name and secret is the API Key.
Am I missing something here or doing something wrong? How can I debug if there are some issues?
Sorry for this late answer, just found your question while googling for something different and hope not too late. If you want to save the credentials in .env, do this in your config\services.php:
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
Then in your .env file
MAILGUN_DOMAIN=sandbox54d5c9ed96434d689f971fd3.mailgun.org
MAILGUN_SECRET=key-e800aa77cbda23ee8471dd5e
In the config\services.php you just tell the key on .env file with:
'setting' => env('KEY_IN_ENV')
Laravel will then check if the key found and get the value from .env file:
KEY_IN_ENV = setting_value
Or simply like this in your config\services.php only:
'mailgun' => [
'domain' => 'sandbox54d5c9ed96434d689f971fd3.mailgun.org',
'secret' => 'key-e800aa77cbda23ee8471dd5e',
],
Good for you.
I am using the Amazon API and get this error while updating my stock from my database to Amazon website:
Caught Exception: Internal Error
Response Status Code: 0
Error Code:
Error Type:
Request ID:
XML:
I read this thread (amazonsellercommunity . com/forums/thread.jspa?messageID=2194823) and then get the error explanation:
<Error><Type>Sender</Type><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</Message><Detail/></Error>
So I thought my MARKETPLACE_ID, MERCHANT_ID, AWS_ACCESS_KEY_ID or AWS_SECRET_ACCESS_KEY could be wrong. But I checked and these informations are correct.
Actually, I don't understand why this error happens... Before, it worked perfectly and since a couple of days it just crash. And I don't change anything in my code. Strange, isn't it?
Edit :
Here is my section code for signature.
define ('DATE_FORMAT', 'Y-m-d\TH:i:s\Z');
define('AWS_ACCESS_KEY_ID', 'ABC...'); // My AWS Access Key Id (20 characters)
define('AWS_SECRET_ACCESS_KEY', 'ABCDEF...'); // My AWS Secret Access Key (40 characters)
define('APPLICATION_NAME', 'MyCompany_AmazonMWS');
define('APPLICATION_VERSION', '0.0.1');
define ('MERCHANT_ID', 'XXXXXXX'); // My Merchant ID
define ('MARKETPLACE_ID', 'XXXXXXX'); // My Marketplace ID
$config = array (
'ServiceURL' => "https://mws.amazonservices.fr",
'ProxyHost' => null,
'ProxyPort' => -1,
'MaxErrorRetry' => 3,
);
$service = new MarketplaceWebService_Client(
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
$config,
APPLICATION_NAME,
APPLICATION_VERSION
);
$parameters = array (
'Marketplace' => MARKETPLACE_ID,
'Merchant' => MERCHANT_ID,
'FeedType' => '_POST_INVENTORY_AVAILABILITY_DATA_',
'FeedContent' => $feedHandle,
'PurgeAndReplace' => false,
'ContentMd5' => base64_encode(md5(stream_get_contents($feedHandle), true)),
);
// and then I do this:
$request = new MarketplaceWebService_Model_SubmitFeedRequest($parameters);
invokeSubmitFeed($service, $request);
If you want to see some parts of my code, just ask.
If I recall correctly, the authentication mechanism for Amazon APIs is sensitive to the current date/time on your machine (which is used in the process of signing the request). Check to see if your date/time is set correctly.
For me it was just an error with my web app passing url escaped strings. The special characters weren't like by amazon and this (not so useful) error came up. Make sure your file names have no url escaped characters.
I solved it (on Ubuntu 14.04 Server) using ntpdate:
First make sure it is installed:
apt-get install ntpdate
And then execute:
ntpdate ntp.ubuntu.com
What I'd like
I want to be able to reset a users password without emailing them. I also need to do this via REST (it's for a kiosk system).
So I need to:
Get user with a specific username
Reset the password of that user
Try as I might, I can't get the user with a username.
The problem
After I've logged in using the admin user via REST I do:
GET on http://mydomain.com/rest/user?name=user.
According to REST documentation, this should get the user with name user.
I get a 200 response, but nothing is returned in the body.
What I've Tried
Get node from ID
Once I've logged in as admin, I can do:
GET on http://mydomain.com/rest/user/1
This works, returning the details of user 1 in the response. But I need to search for a user by username.
Different GETs
GET on http://mydomain.com/rest/user/admin
GET on http://mydomain.com/rest/user/account/name/admin
GET on http://mydomain.com/rest/user?account[name]=admin
GET on http://mydomain.com/rest/user?uid=1
GET on http://mydomain.com/rest/user/retrieve?uid=1
GET on http://mydomain.com/rest/user?account[uid]=1
All these fail.
Nodes instead of users
GET on http://mydomain.com/rest/node/1 works, but http://mydomain.com/rest/node?nid=1 gives me a 200 response with nothing in the body.
List of all users
GET on http://mydomain.com/rest/user/ doesn't show a list of all users either. I get a 200 with empty body again.
Further Details
I'm working with a Drupal 6.22 install.
I've installed the services module (3.0 RC1) and REST Server (2.0 beta 1).
I've got the session authentication module installed.
I've tried the above with the session authentication switched on and with it off.
I've enabled all node resources and user resources for the REST endpoint I've set up.
I've tried the above with and without clean URLs and nothing seems to make a difference.
Question
How do I get a user with a specific username? What am I doing wrong?
Update
I've uninstalled then reinstalled Services module, I've done the same with the REST server. I've also rolled back my version of CTools to the latest recommended one. I've added a brand new service in case it was corrupted. Nothing I do works. Frustrating!
Update 2
I've found the problem, but would like a more permanent solution. It turns out it was an error because of table naming. See my current accepted answer.
Im sorry this is so frustrating for you. Im the maintainer for services module and were really working on the documentation but I thought I would answer here to just get you moving along.
The reason you are not getting any of the data you want is because the parameters you are passing are wrong.
If you look at user_resource.inc index is defined as follows
'index' => array(
'file' => array('type' => 'inc', 'module' => 'services', 'name' => 'resources/user_resource'),
'callback' => '_user_resource_index',
'args' => array(
array(
'name' => 'page',
'optional' => TRUE,
'type' => 'int',
'description' => 'The zero-based index of the page to get, defaults to 0.',
'default value' => 0,
'source' => array('param' => 'page'),
),
array(
'name' => 'fields',
'optional' => TRUE,
'type' => 'string',
'description' => 'The fields to get.',
'default value' => '*',
'source' => array('param' => 'fields'),
),
array(
'name' => 'parameters',
'optional' => TRUE,
'type' => 'array',
'description' => 'Parameters',
'default value' => array(),
'source' => array('param' => 'parameters'),
),
),
'access arguments' => array('access user profiles'),
'access arguments append' => FALSE,
),
Notice the third argument, parameters.
You can do all sorts of fun stuff with the index query as long as it is turned on, but what you havnt tried is ?parameters[name]=user Example below
When I make a request to http://test/api/user?parameters[name]=gdsfgsdfgsdfg&fields=name,uid
I get returned
[
{
"name":"gdsfgsdfgsdfg",
"uid":"36",
"uri":"http:\/\/test\/api\/user\/36"
}
]
Notice i also added some fields, uid and name. Obviously these are optional but it shows you the power of the index query. The same applies to nodes.
I hope this helps.
Try something like:
GET on http://mydomain.com/rest/user?parameters[name]=admin
This worked for me in Drupal7. Not sure if it'll be the same for 6. But I also had no issues with getting the index of all users using GET on http://mydomain.com/rest/user/
I found the issue. It's an error/bug with the Services module in the setup I have.
From the services.module file
449 // Now implode that array into an actual WHERE clause.
450 $where = !empty($where) ? ' WHERE '. implode(' AND ', $where) : '';
451 // Run through db_rewrite_sql to make sure proper access checks are applied.
// **** Error logged for this next line ****
452 $sql = "SELECT $fields FROM {$table} $where ORDER BY $order"; // <-- Error was logged for this line
453 $sql = db_rewrite_sql($sql);
454 $result = db_query_range($sql, $parameters, $page * 20, 20);
455 return $result;
The error
Table '<REDACTED>_drup1.users' doesn't exist query: SELECT * FROM users ORDER BY created DESC LIMIT 0, 20 in /<REDACTED>/sites/all/modules/services/services.module on line 455.
The users table in my installation is called drup_users. When I change line 452 to
452 $sql = "SELECT $fields FROM drup_{$table} $where ORDER BY $order";
It works. I'd be interested in knowing how I can have a more permanent solution. I ran update.php several times and it didn't fix this.