-
Notifications
You must be signed in to change notification settings - Fork 130
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
[GH-971] Support Jira migration to Oauth #995
Changes from all commits
aad0dbb
13dcb55
7e27ce0
5614754
1055626
18f2deb
cdd9d2a
cf7e02a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ import ( | |
"golang.org/x/oauth2" | ||
|
||
"github.com/mattermost/mattermost-plugin-jira/server/utils" | ||
"github.com/mattermost/mattermost-plugin-jira/server/utils/kvstore" | ||
"github.com/mattermost/mattermost-plugin-jira/server/utils/types" | ||
) | ||
|
||
|
@@ -29,6 +30,7 @@ type cloudOAuthInstance struct { | |
JiraBaseURL string | ||
CodeVerifier string | ||
CodeChallenge string | ||
JWTInstance *cloudInstance | ||
} | ||
|
||
type CloudOAuthConfigure struct { | ||
|
@@ -56,7 +58,7 @@ const ( | |
PKCEByteArrayLength = 32 | ||
) | ||
|
||
func (p *Plugin) installCloudOAuthInstance(rawURL, clientID, clientSecret string) (string, *cloudOAuthInstance, error) { | ||
func (p *Plugin) installCloudOAuthInstance(rawURL string) (string, *cloudOAuthInstance, error) { | ||
jiraURL, err := utils.CheckJiraURL(p.GetSiteURL(), rawURL, false) | ||
if err != nil { | ||
return "", nil, err | ||
|
@@ -70,21 +72,51 @@ func (p *Plugin) installCloudOAuthInstance(rawURL, clientID, clientSecret string | |
return "", nil, err | ||
} | ||
|
||
instance := &cloudOAuthInstance{ | ||
InstanceCommon: newInstanceCommon(p, CloudOAuthInstanceType, types.ID(jiraURL)), | ||
MattermostKey: p.GetPluginKey(), | ||
JiraClientID: clientID, | ||
JiraClientSecret: clientSecret, | ||
JiraBaseURL: rawURL, | ||
CodeVerifier: params.CodeVerifier, | ||
CodeChallenge: params.CodeChallenge, | ||
newInstance := &cloudOAuthInstance{ | ||
InstanceCommon: newInstanceCommon(p, CloudOAuthInstanceType, types.ID(jiraURL)), | ||
MattermostKey: p.GetPluginKey(), | ||
JiraBaseURL: rawURL, | ||
CodeVerifier: params.CodeVerifier, | ||
CodeChallenge: params.CodeChallenge, | ||
} | ||
|
||
if err = p.InstallInstance(instance); err != nil { | ||
return "", nil, err | ||
existingInstance, err := p.instanceStore.LoadInstance(types.ID(jiraURL)) | ||
if err != nil && !errors.Is(err, kvstore.ErrNotFound) { | ||
return "", nil, errors.Wrapf(err, "failed to load existing jira instance. ID: %s", jiraURL) | ||
} | ||
|
||
return jiraURL, instance, err | ||
// Handle backwards compatibility with existing JWT instance | ||
if existingInstance != nil { | ||
if existingInstance.Common().Type == CloudOAuthInstanceType { | ||
oauthInstance, ok := existingInstance.(*cloudOAuthInstance) | ||
if !ok { | ||
return "", nil, errors.Wrapf(err, "failed to assert existing cloud-oauth instance as cloudOAuthInstance. ID: %s", jiraURL) | ||
} | ||
|
||
newInstance.JWTInstance = oauthInstance.JWTInstance | ||
if newInstance.JWTInstance != nil { | ||
p.API.LogDebug("Installing cloud-oauth over existing cloud-oauth instance. Carrying over existing saved JWT instance.") | ||
} else { | ||
p.API.LogDebug("Installing cloud-oauth over existing cloud-oauth instance. There exists no previous JWT instance to carry over.") | ||
} | ||
} else if existingInstance.Common().Type == CloudInstanceType { | ||
jwtInstance, ok := existingInstance.(*cloudInstance) | ||
if !ok { | ||
return "", nil, errors.Wrapf(err, "failed to assert existing cloud instance as cloudInstance. ID: %s", jiraURL) | ||
} | ||
|
||
newInstance.JWTInstance = jwtInstance | ||
p.API.LogDebug("Installing cloud-oauth over existing cloud JWT instance. Carrying over existing saved JWT instance.") | ||
} | ||
} else { | ||
p.API.LogDebug("Installing new cloud-oauth instance. There exists no previous JWT instance to carry over.") | ||
} | ||
|
||
if err = p.InstallInstance(newInstance); err != nil { | ||
return "", nil, errors.Wrapf(err, "failed to install cloud-oauth instance. ID: %s", jiraURL) | ||
} | ||
|
||
return jiraURL, newInstance, nil | ||
} | ||
|
||
func (ci *cloudOAuthInstance) GetClient(connection *Connection) (Client, error) { | ||
|
@@ -98,6 +130,13 @@ func (ci *cloudOAuthInstance) GetClient(connection *Connection) (Client, error) | |
func (ci *cloudOAuthInstance) getClientForConnection(connection *Connection) (*jira.Client, *http.Client, error) { | ||
oauth2Conf := ci.GetOAuthConfig() | ||
ctx := context.Background() | ||
|
||
// Checking if this user's connection is for a JWT instance | ||
if ci.JWTInstance != nil && connection.OAuth2Token == nil { | ||
ci.Plugin.API.LogDebug("Returning a JWT token client since the stored JWT instance is not nil and the user's oauth token is nil") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you thinking we should remove log statements like this in a following release? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mickmister Yes, we will remove these in a later release. These are just to check if the code executed as we expected it to. |
||
return ci.JWTInstance.getClientForConnection(connection) | ||
} | ||
|
||
tokenSource := oauth2Conf.TokenSource(ctx, connection.OAuth2Token) | ||
client := oauth2.NewClient(ctx, tokenSource) | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -590,7 +590,7 @@ func (p *Plugin) initCreateCloudOAuthInstance(f *flow.Flow, submission map[strin | |||
jiraURL = fmt.Sprintf("https://%s.atlassian.net", jiraURL) | ||||
} | ||||
|
||||
jiraURL, instance, err := p.installCloudOAuthInstance(jiraURL, "", "") | ||||
jiraURL, instance, err := p.installCloudOAuthInstance(jiraURL) | ||||
if err != nil { | ||||
return "", nil, nil, err | ||||
} | ||||
|
@@ -633,9 +633,20 @@ func (p *Plugin) submitCreateCloudOAuthInstance(f *flow.Flow, submission map[str | |||
return "", nil, nil, errors.New("no Jira OAuth Client Secret is present in the request") | ||||
} | ||||
|
||||
jiraURL, instance, err := p.installCloudOAuthInstance(jiraURL, clientID, clientSecret) | ||||
existingInstance, err := p.instanceStore.LoadInstance(types.ID(jiraURL)) | ||||
if err != nil { | ||||
return "", nil, nil, err | ||||
return "", nil, nil, errors.Wrap(err, "failed to load existing cloud-oauth instance") | ||||
} | ||||
|
||||
instance, ok := existingInstance.(*cloudOAuthInstance) | ||||
if !ok { | ||||
return "", nil, nil, errors.Errorf("existing instance is not a cloud-oauth instance. ID: %s", jiraURL) | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
mattermost-plugin-jira/server/setup_flow.go Line 583 in 06a02e8
|
||||
} | ||||
|
||||
instance.JiraClientID = clientID | ||||
instance.JiraClientSecret = clientSecret | ||||
if err = p.instanceStore.StoreInstance(instance); err != nil { | ||||
Comment on lines
+646
to
+648
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are we storing the clientID and clientSecret of the new oauth instance to the existing one? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's not really a "new" instance here. There will always be an existing one in the kv store at this point of the setup. There are multiple stages to the setup flow and this is the second one |
||||
return "", nil, nil, errors.Wrap(err, "failed to store cloud-oauth instance") | ||||
} | ||||
|
||||
return stepInstalledJiraApp, flow.State{ | ||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@esarafianou This is because at the time of "installing" the
cloud-oauth
instance, we haven't gotten to the point of the setup where we provide the client id & client secret. That is instead in the second step of the setup process. Before this PR, we were callinginstallCloudOAuthInstance
on that step too, though we have changed how that works by just setting the values on the saved instance rather than going through that same function call againmattermost-plugin-jira/server/setup_flow.go
Lines 646 to 648 in 06a02e8