Skip to content

Commit 3bffd9b

Browse files
Merge branch 'master' into CPM-331
2 parents 2ef7f54 + c6cbdac commit 3bffd9b

File tree

212 files changed

+10223
-1699
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

212 files changed

+10223
-1699
lines changed

.circleci/config.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ version: 2
22
jobs:
33
build:
44
machine:
5-
image: ubuntu-1604:201903-01
5+
image: ubuntu-2004:202111-02
66
steps:
77
- checkout
88
- run: make build
99

1010
deploy_staging:
1111
machine:
12-
image: ubuntu-1604:201903-01
12+
image: ubuntu-2004:202111-02
1313
steps:
1414
- checkout
1515
- add_ssh_keys
@@ -19,7 +19,7 @@ jobs:
1919

2020
deploy_production:
2121
machine:
22-
image: ubuntu-1604:201903-01
22+
image: ubuntu-2004:202111-02
2323
steps:
2424
- checkout
2525
- add_ssh_keys
@@ -42,4 +42,9 @@ workflows:
4242
- deploy_production:
4343
filters:
4444
branches:
45-
only: master
45+
only: master
46+
- deploy_staging?:
47+
type: approval
48+
- deploy_staging:
49+
requires:
50+
- deploy_staging?

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
content/apps/ @akeneo/squad-octopus

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:10-alpine
1+
FROM node:16-alpine
22
RUN apk add yarn
33
RUN apk add openssh-client
4-
RUN apk add rsync
4+
RUN apk add rsync

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ build: yarn-install
2020
$(DOCKER_RUN) $(DOCKER_IMAGE_TAG) yarn gulp create-dist
2121

2222
deploy: build
23-
$(DOCKER_RUN) -v /etc/passwd:/etc/passwd:ro -v $${SSH_AUTH_SOCK}:/ssh-auth.sock:ro -e SSH_AUTH_SOCK=/ssh-auth.sock $(DOCKER_IMAGE_TAG) rsync --no-v -e "ssh -q -p $${PORT} -o StrictHostKeyChecking=no" -az --delete dist/ akeneo@$${HOSTNAME}:/var/www/html
23+
$(DOCKER_RUN) -v /etc/passwd:/etc/passwd:ro -v $${SSH_AUTH_SOCK}:/ssh-auth.sock:ro -e SSH_AUTH_SOCK=/ssh-auth.sock $(DOCKER_IMAGE_TAG) rsync --no-v -e "ssh -q -p $${PORT} -o StrictHostKeyChecking=no -o PubkeyAcceptedKeyTypes=+ssh-rsa" -az --delete dist/ akeneo@$${HOSTNAME}:/var/www/html

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,19 @@ Then click on _Rerun_.
4646

4747
As our YAML Swagger spec uses references and links, it is considered as non-valid.
4848
During the build, we generate a valid JSON specification that is put under the `content/swagger` folder. Don't forget to version it if you made any change into the YAML Swagger spec.
49+
50+
### Custom properties
51+
52+
Our Swagger spec is extended with [custom properties](https://swagger.io/docs/specification/2-0/swagger-extensions/):
53+
54+
| Property | Type | Description |
55+
|--------------------------|-------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
56+
| `x-from-version` | `string` | Indicates the version the property was added to the API. In the user documentation, hides the property from payload descriptions that doesn't match the selected API version. |
57+
| `x-examples-per-version` | [[Example object](#example-object)] | Allows to set a payload example for a specific version. Use as a [Response object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#responsesObject) property. |
58+
59+
#### Example object
60+
61+
| Property | Type | Description |
62+
|-------------|----------|----------------------------|
63+
| `x-version` | `string` | API version of the example |
64+
| `x-example` | `any` | Example payload content |

content/apps/access-scopes.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Access scopes
2+
3+
::: warning
4+
This feature is available on all SaaS environments and only since v6 for other types of environments.
5+
:::
6+
7+
8+
Part of the app authorization process requires specifying which parts of Akeneo PIM data the App needs to access.
9+
An App can request any of the access scopes listed below.
10+
11+
::: warning
12+
**Akeneo PIM may not grant all requested scopes.**
13+
This is up to your App to check which scopes were granted when you receive an Access Token.
14+
For example, the Community edition will not be able to grant you scopes related to the Asset Manager because
15+
it's a feature only available in the Enterprise edition.
16+
:::
17+
18+
## Available authorization scopes
19+
20+
| Scope | Grants access to |
21+
|-------------------------------------------------------------------------|------------------------------------------------------------------|
22+
| `read_products` | Read products |
23+
| `write_products` | Write products |
24+
| `delete_products` | Remove products |
25+
| `read_catalog_structure` | Read attributes, attribute groups, families and family variants |
26+
| `write_catalog_structure` | Write attributes, attribute groups, families and family variants |
27+
| `read_attribute_options` | Read attribute options |
28+
| `write_attribute_options` | Write attribute options |
29+
| `read_categories` | Read categories |
30+
| `write_categories` | Write categories |
31+
| `read_channel_localization` | Read locales and currencies |
32+
| `read_channel_settings` | Read channels |
33+
| `write_channel_settings` | Write channels |
34+
| `read_association_types` | Read association types |
35+
| `write_association_types` | Write association types |
36+
| `read_asset_families` <span class="label label-ee">EE</span> | Read asset families |
37+
| `write_asset_families` <span class="label label-ee">EE</span> | Write assets families |
38+
| `read_assets` <span class="label label-ee">EE</span> | Read assets |
39+
| `write_assets` <span class="label label-ee">EE</span> | Write assets |
40+
| `delete_assets` <span class="label label-ee">EE</span> | Remove assets |
41+
| `read_reference_entities` <span class="label label-ee">EE</span> | Read reference entities |
42+
| `write_reference_entities` <span class="label label-ee">EE</span> | Write reference entities |
43+
| `read_reference_entity_records` <span class="label label-ee">EE</span> | Read reference entity records |
44+
| `write_reference_entity_records` <span class="label label-ee">EE</span> | Write reference entity records |
45+
46+
## Available authentication scopes
47+
48+
| Scope | Grants access to |
49+
|-----------|------------------------------------------------------------|
50+
| `openid` | Read user id |
51+
| `profile` | Read user first name and last name (from PIM user profile) |
52+
| `email` | Read user email (from PIM user profile) |
53+
54+
::: panel-link Next step [How to test my App ?](/apps/how-to-test-my-app.html)
55+
:::

content/apps/create-app.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Create an App (with code samples)
2+
3+
::: warning
4+
This feature is available on all SaaS environments and only since v6 for other types of environments.
5+
:::
6+
7+
In this tutorial, we provide a guide on how to implement the required parts of your App
8+
for the activation process based on OAuth 2.0 with Authorization Code.
9+
At the end of this tutorial, your App will receive an Access Token and will be able to call the REST API of a PIM.
10+
11+
::: warning
12+
Examples in this tutorial use languages without any framework or library and, consequently, don't follow
13+
all the recommended best practices. We **strongly** encourage you to adapt those examples with the framework or
14+
library of your choice.
15+
:::
16+
17+
## Prerequisites
18+
19+
You must have valid [OAuth 2.0 client credentials](/apps/using-oauth2.html#credentials).
20+
21+
## Activation URL
22+
23+
First, your application must expose an activation URL.
24+
25+
In our example, we won't do additional steps (like authentification), so we will launch the Authorization Request
26+
immediately in this Activation URL.
27+
28+
29+
!!!include(content/apps/create-app/activate-php.md)!!!
30+
!!!include(content/apps/create-app/activate-nodejs.md)!!!
31+
!!!include(content/apps/create-app/activate-python.md)!!!
32+
!!!include(content/apps/create-app/activate-java.md)!!!
33+
34+
## Callback URL
35+
36+
Then, your application must expose a callback URL.
37+
38+
39+
!!!include(content/apps/create-app/callback-php.md)!!!
40+
!!!include(content/apps/create-app/callback-nodejs.md)!!!
41+
!!!include(content/apps/create-app/callback-python.md)!!!
42+
!!!include(content/apps/create-app/callback-java.md)!!!
43+
44+
45+
46+
::: info
47+
The Code Challenge is documented [here](/apps/using-oauth2.html#whats-the-code-challenge).
48+
:::
49+
50+
And that's it!
51+
At the end of this process, you receive the following response with an `access_token`:
52+
53+
```json
54+
{
55+
"access_token": "Y2YyYjM1ZjMyMmZlZmE5Yzg0OTNiYjRjZTJjNjk0ZTUxYTE0NWI5Zm",
56+
"token_type": "bearer",
57+
"scope": "read_products write_products"
58+
}
59+
```
60+
61+
You can use this token to call the Akeneo PIM REST API.
62+
63+
::: tips
64+
Reminder: our documentation is [open-source](https://github.com/akeneo/pim-api-docs). Feel free to contribute with languages we're not experts at.
65+
:::
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
```java [activate:Java Spring]
2+
import java.security.SecureRandom;
3+
4+
import javax.servlet.http.HttpServletRequest;
5+
import javax.servlet.http.HttpServletResponse;
6+
import javax.servlet.http.HttpSession;
7+
8+
import org.apache.tomcat.util.buf.HexUtils;
9+
10+
import org.springframework.web.bind.annotation.GetMapping;
11+
import org.springframework.web.bind.annotation.RestController;
12+
13+
public class App {
14+
static final String OAUTH_CLIENT_ID = "CLIENT_ID";
15+
static final String OAUTH_SCOPES = "read_products write_products";
16+
17+
@GetMapping("/activate")
18+
public void activate(HttpServletRequest request, HttpSession session, HttpServletResponse response) throws Exception {
19+
// Create a random state for preventing cross-site request forgery
20+
byte[] randomBytes = new byte[10];
21+
new SecureRandom().nextBytes(randomBytes);
22+
String state = HexUtils.toHexString(randomBytes);
23+
24+
Object pimUrl = request.getParameter("pim_url");
25+
if (pimUrl == null) {
26+
throw new Exception("Missing PIM URL in the query");
27+
}
28+
29+
// Store in the user session the state and the PIM URL
30+
session.setAttribute("oauth2_state", state);
31+
session.setAttribute("pim_url", pimUrl.toString());
32+
33+
// Build url for the Authorization Request
34+
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1
35+
String authorizeUrl = pimUrl + "/connect/apps/v1/authorize" + "?response_type=code" + "&client_id=" + OAUTH_CLIENT_ID
36+
+ "&scope=" + OAUTH_SCOPES + "&state=" + state;
37+
38+
// Redirect the user to the Authorization URL
39+
response.sendRedirect(authorizeUrl);
40+
}
41+
}
42+
```
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
```js [activate:NodeJS]
2+
3+
params // data from your request handling
4+
storage // your own memory system
5+
6+
// Retrieve GET query params from your own framework / http handler
7+
const { pim_url: pimUrl } = params;
8+
9+
// Retrieve your app's Client ID with your own system
10+
const clientId = storage.get("CLIENT_ID");
11+
12+
// Set the access scopes, take care of the 254 chars max !
13+
const scopes = 'read_products write_products';
14+
15+
// The activate URL should have the pim_url param
16+
if (!pimUrl) {
17+
// Return a Bad request response via your own framework / http server
18+
return response(502, { message: "Bad request" });
19+
}
20+
21+
// Store the PIM url value with your own system
22+
storage.set("PIM_URL", pimUrl);
23+
24+
// Set a new security state secret and store the value with your own system
25+
const state = require('crypto').randomBytes(32).toString("hex");
26+
storage.set("APP_STATE", state);
27+
28+
// Construct the PIM authorization url, it will be called on "connect" / "open" button
29+
const redirect_url = `${pimUrl}/connect/apps/v1/authorize` +
30+
`?response_type=code` +
31+
`&client_id=${clientId}` +
32+
`&scope=${scopes}` +
33+
`&state=${state}`
34+
35+
// Set the redirection response with your own framework / http server
36+
return redirect(redirect_url);
37+
38+
```
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
```php [activate:PHP]
2+
3+
// Let's create an `activate.php` file
4+
5+
const OAUTH_CLIENT_ID = '<CLIENT_ID>';
6+
const OAUTH_SCOPES = 'read_products write_products';
7+
8+
session_start();
9+
10+
$pimUrl = $_GET['pim_url'];
11+
if (empty($pimUrl)) {
12+
exit('Missing PIM URL in the query');
13+
}
14+
15+
// create a random state for preventing cross-site request forgery
16+
$state = bin2hex(random_bytes(10));
17+
18+
// Store in the user session the state and the PIM URL
19+
$_SESSION['oauth2_state'] = $state;
20+
$_SESSION['pim_url'] = $pimUrl;
21+
22+
// Build the parameters for the Authorization Request
23+
// https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1
24+
$authorizeUrlParams = http_build_query([
25+
'response_type' => 'code',
26+
'client_id' => OAUTH_CLIENT_ID,
27+
'scope' => OAUTH_SCOPES,
28+
'state' => $state,
29+
]);
30+
31+
// Build the url for the Authorization Request using the PIM URL
32+
$authorizeUrl = $pimUrl . '/connect/apps/v1/authorize?' . $authorizeUrlParams;
33+
34+
// Redirect the user to the Authorization URL
35+
header('Location: ' . $authorizeUrl);
36+
```

0 commit comments

Comments
 (0)