Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mattermost Installation Flow #4534

Open
wants to merge 4 commits into
base: matiasb/mattermost-chatops
Choose a base branch
from

Conversation

ravishankar15
Copy link
Contributor

What this PR does

This PR covers the installation flow,

  1. The user hits the /mattermost/setup path which gives an manifest json link with the auth_token
  2. The user then navigates to Mattermost portal and use /apps command with the manifest url to install the app in the instance
  3. The on_install and bindings call back will reach our server in which we can create and link the org and user

Which issue(s) this PR closes

Closes [issue link here]

Checklist

  • Unit, integration, and e2e (if applicable) tests updated
  • Documentation added (or pr:no public docs PR label added if not required)
  • Added the relevant release notes label (see labels prefixed w/ release:). These labels dictate how your PR will
    show up in the autogenerated release notes.

Mattermost install flow

remove utils

Fix jwt error

Add install flow details

Fix formatting

Fix auth token
@ravishankar15 ravishankar15 requested a review from a team as a code owner June 14, 2024 04:09
@ravishankar15
Copy link
Contributor Author

@matiasb Can you check this PR for the backend changes ! if the flow looks good I will make the front end changes to show the installation link to the user.

@joeyorlando
Copy link
Contributor

this seems to be the start of #96

Copy link
Contributor

@matiasb matiasb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for start working on this! Looking good, added a few comments/questions.
It will be nice to start adding some initial tests too.

permission_classes = (IsAuthenticated, RBACPermission)

rbac_permissions = {
"get": [RBACPermission.Permissions.INTEGRATIONS_WRITE],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to move this logic to the backend itself, maybe using the existing GetChannelVerificationCode? (although it could be confusing because in this case the code would be for a mattermost instance instead of a telegram or msteams channel), or defining a new optional messaging backend step for this. In an ideal world, it should be possible to write a messaging backend without changing any code in the other apps. Will give it some thought.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gave some thought. One way it could be is via polymorphic association we could have a single model to generate the tokens for each backend apps with a type field but that might be slightly complicated to unify that approach for the existing apps token implementation.

engine/apps/api/views/organization.py Outdated Show resolved Hide resolved
engine/apps/mattermost/views.py Outdated Show resolved Hide resolved
engine/apps/mattermost/views.py Outdated Show resolved Hide resolved


class MattermostBindings(APIView):
authentication_classes = (MattermostWebhookAuthTokenAuthentication,)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think bindings should authenticate the user behind the request instead (or too), right?

Copy link
Contributor Author

@ravishankar15 ravishankar15 Jun 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call is to return the bindings supported by our app hence it has the token authentication. Once we decide on the bindings like /alert we will create separate paths (or reuse old ones) in which case those paths will have authentication of its own. Might also include the same token

@ravishankar15 ravishankar15 requested a review from a team as a code owner June 25, 2024 16:10
"requested_locations": ["/in_post", "/post_menu", "/command"],
"on_install": self._build_on_install_callback(auth_token=auth_token),
"bindings": self._build_bindings_callback(auth_token=auth_token),
"http": {"root_url": live_settings.MATTERMOST_WEBHOOK_HOST},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was just reviewing my notes and draft code, and I think that my original plan was to use JWT for the app auth/link (see also this example, and that's what the authenticate function was supposed to do in the WIP I shared; also, that should allow us identify the user making requests to OnCall from Mattermost).

So, I think, we could generate a random token to store in a Mattermost Server model (similar to the one in the gist). This token will be asked to the user during install, and we can then link the Mattermost App with Server (and the respective org).

The flow I'm imagining will be something like:

  • Admin user goes to a "setup mattermost" endpoint
    • this endpoint will setup a server instance with a generated token
    • returns a manifest URL (no auth, this is public info) with the use_jwt flag enabled
  • User install app using the manifest URL; it should be asked for the generated secret
    • manifest includes an install URL (this URL could include the org public ID, and it should require a valid and matching token/secret, server-side).
    • when install endpoint is hit, this will complete the (OnCall Mattermost) server setup

And that's it (?). From that moment on, app should be installed and be able to talk to OnCall, and OnCall should have the information for the mattermost app linked to a specific org.

Makes sense? Sorry I didn't try to summarize this before, but I couldn't find the time to understand my notes and test a few things until now. I think that the basics for this are in the shared gist.

Let me know if you think this won't work, or if you prefer me to work on a better PoC following the above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi ! Correct me if my understanding is right,

  1. We have two endpoints,
    • /manifest --> Returns the manifest json
    • /install --> The on_install call back
  2. Do we have to authenticate the /manifest endpoint ? If No then wouldn't that mean this endpoint can be hit by anyone of the internet users ? Like I can hit the server of any customers oncall instance and spam them right ?
  3. When the user hits the Setup Mattermost We generate the JWT signing secret and create the JWT token with org id in it. The JWT token will be shared in the UI along with the Mattermost json url. When the user installs the app the Mattermost app will send the jwt token in the request header. For authenticating when we receive the jwt token we get the org id from the jwt payload and using the org id we get the signing secret from our DB for that org id and then verify the signature before proceeding Is that right ?

If (3) is the expected behaviour. When we do the link-user like linking the oncall user to Mattermost user ? I believe we will generate a separate token which needs to be sent when the user types /link-user command from Mattermost ? using which we link the user.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi ! Correct me if my understanding is right,

1. We have two endpoints,
   
   * `/manifest`  --> Returns the manifest json
   * `/install` --> The on_install call back

Right.

2. Do we have to authenticate the `/manifest` endpoint ? If No then wouldn't that mean this endpoint can be hit by anyone of the internet users ? Like I can hit the server of any customers oncall instance and spam them right ?

Hm.. Not exactly, because /install will require a valid JWT token. Also we should generate the manifest.json using org id info. So, when an admin generates the JWT token, they also get a URL to the manifest with a param indicating the org ID, which is used in the rendered /install URL. Then, anyone will be able to get the base manifest.json, but to make things work you still need a JWT token and (the correspondent) an org ID... we could also require a fresh enough token before allowing installation. Makes sense?

3. When the user hits the `Setup Mattermost` We generate the JWT signing secret and create the JWT token with org id in it. The JWT token will be shared in the UI along with the Mattermost json url. When the user installs the app the Mattermost app will send the jwt token in the request header. For authenticating when we receive the jwt token we get the org id from the jwt payload and using the org id we get the signing secret from our DB for that org id and then verify the signature before proceeding Is that right ?

Yeah, something like that is what I was thinking.

If (3) is the expected behaviour. When we do the link-user like linking the oncall user to Mattermost user ? I believe we will generate a separate token which needs to be sent when the user types /link-user command from Mattermost ? using which we link the user.

That's correct, we will still need some link-user command (for which we could generate a token, similar to telegram or msteams flows) to bind an OnCall account with a Mattermost user.

How does it sound?

Copy link
Contributor Author

@ravishankar15 ravishankar15 Jul 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed ! yeah /install will require the JWT which will have the org id but for the /manifest endpoint we should be using a token which maps to the org like we have in the current state of the PR ? or should we just send the org_id as plain text in the manifest url like /manifest?org_id=<ORG_ID> ?

Hm.. Not exactly, because /install will require a valid JWT token. Also we should generate the manifest.json using org id info. So, when an admin generates the JWT token, they also get a URL to the manifest with a param indicating the org ID, which is used in the rendered /install URL. Then, anyone will be able to get the base manifest.json, but to make things work you still need a JWT token and (the correspondent) an org ID... we could also require a fresh enough token before allowing installation. Makes sense?

I think overall I got the context expect the above point mentioned I will start making the changes and will update the PR over this week.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed ! yeah /install will require the JWT which will have the org id but for the /manifest endpoint we should be using a token which maps to the org like we have in the current state of the PR ? or should we just send the org_id as plain text in the manifest url like /manifest?org_id=<ORG_ID> ?

👍 I think using the org_id as a query param should be ok, doesn't it? But if we are including the org id as part of the secret maybe we can even omit it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah makes sense ! I think I will skip the org id in the manifest and use the org id in the secret ! will start making the changes in this week !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants