Skip to content

Commit fc19a8a

Browse files
committed
Functionality is working, need to polish and write tests. Currently disabled
1 parent 0078629 commit fc19a8a

File tree

9 files changed

+129
-37
lines changed

9 files changed

+129
-37
lines changed

coderd/coderd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ func New(options *Options) *API {
620620
r.Use(
621621
apiKeyMiddleware,
622622
)
623-
r.Post("/upgrade-to-oidc", api.postUpgradeToOIDC)
623+
r.Post("/", api.postConvertToOauth)
624624
})
625625
})
626626
r.Group(func(r chi.Router) {

coderd/database/dbauthz/dbauthz.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1858,7 +1858,8 @@ func (q *querier) InsertUserLink(ctx context.Context, arg database.InsertUserLin
18581858
}
18591859

18601860
func (q *querier) InsertUserOauthMergeState(ctx context.Context, arg database.InsertUserOauthMergeStateParams) (database.OauthMergeState, error) {
1861-
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceSystem); err != nil {
1861+
// TODO: @emyrk this permission feels right?
1862+
if err := q.authorizeContext(ctx, rbac.ActionCreate, rbac.ResourceAPIKey.WithOwner(arg.UserID.String())); err != nil {
18621863
return database.OauthMergeState{}, err
18631864
}
18641865

coderd/database/dbmetrics/dbmetrics.go

Lines changed: 0 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbmock/dbmock.go

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/userauth.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"fmt"
88
"net/http"
99
"net/mail"
10-
"net/url"
1110
"sort"
1211
"strconv"
1312
"strings"
@@ -34,7 +33,7 @@ import (
3433
"github.com/coder/coder/codersdk"
3534
)
3635

37-
func (api *API) postUpgradeToOIDC(rw http.ResponseWriter, r *http.Request) {
36+
func (api *API) postConvertToOauth(rw http.ResponseWriter, r *http.Request) {
3837
var (
3938
ctx = r.Context()
4039
auditor = api.Auditor.Load()
@@ -111,11 +110,18 @@ func (api *API) postUpgradeToOIDC(rw http.ResponseWriter, r *http.Request) {
111110
return
112111
}
113112

114-
// Redirect the user back to where they were after the account merge.
115-
redirectURL := fmt.Sprintf("/api/v2/users/%s/callback?redirect=%s&oidc_merge_state=%s", oauthID, url.QueryEscape(r.URL.Path), mergeState.StateString)
113+
httpapi.Write(ctx, rw, http.StatusCreated, codersdk.OauthConversionResponse{
114+
StateString: mergeState.StateString,
115+
ExpiresAt: mergeState.ExpiresAt,
116+
OAuthID: mergeState.OauthID,
117+
UserID: mergeState.UserID,
118+
})
116119

117-
// Redirect the user to the normal OIDC flow with the special 'oidc_merge_state' state string.
118-
http.Redirect(rw, r, redirectURL, http.StatusTemporaryRedirect)
120+
//// Redirect the user back to where they were after the account merge.
121+
//redirectURL := fmt.Sprintf("/api/v2/users/%s/callback?redirect=%s&oidc_merge_state=%s", oauthID, url.QueryEscape(r.URL.Path), mergeState.StateString)
122+
//
123+
//// Redirect the user to the normal OIDC flow with the special 'oidc_merge_state' state string.
124+
//http.Redirect(rw, r, redirectURL, http.StatusTemporaryRedirect)
119125
}
120126

121127
// Authenticates the user with an email and password.
@@ -968,7 +974,8 @@ func (api *API) oauthLogin(r *http.Request, params oauthLoginParams) (*http.Cook
968974
UserID: user.ID,
969975
StateString: params.State.StateString,
970976
})
971-
if err == nil && mergeState.ExpiresAt.Before(time.Now()) {
977+
var _ = mergeState
978+
if err == nil {
972979
return httpError{
973980
code: http.StatusForbidden,
974981
msg: "Hey! This upgrade would have worked if I let it",

codersdk/users.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ type LoginWithPasswordResponse struct {
109109
SessionToken string `json:"session_token" validate:"required"`
110110
}
111111

112+
type OauthConversionResponse struct {
113+
StateString string `json:"state_string"`
114+
ExpiresAt time.Time `json:"expires_at"`
115+
OAuthID string `json:"oauth_id"`
116+
UserID uuid.UUID `json:"user_id"`
117+
}
118+
112119
type CreateOrganizationRequest struct {
113120
Name string `json:"name" validate:"required,username"`
114121
}

site/src/api/api.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,33 @@ export const login = async (
107107
return response.data
108108
}
109109

110+
export const convertToOauth = async (
111+
email: string,
112+
password: string,
113+
oauth_provider: string,
114+
): Promise<TypesGen.OauthConversionResponse | undefined> => {
115+
const payload = JSON.stringify({
116+
email,
117+
password,
118+
oauth_provider,
119+
})
120+
121+
try {
122+
const response = await axios.post<TypesGen.OauthConversionResponse>("/api/v2/users/upgrade-to-oidc",
123+
payload,
124+
{
125+
headers: { ...CONTENT_TYPE_JSON },
126+
})
127+
return response.data
128+
} catch (error) {
129+
if (axios.isAxiosError(error) && error.response?.status === 401) {
130+
return undefined
131+
}
132+
133+
throw error
134+
}
135+
}
136+
110137
export const logout = async (): Promise<void> => {
111138
await axios.post("/api/v2/users/logout")
112139
}

site/src/api/typesGenerated.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,14 @@ export interface OIDCConfig {
544544
readonly icon_url: string
545545
}
546546

547+
// From codersdk/users.go
548+
export interface OauthConversionResponse {
549+
readonly state_string: string
550+
readonly expires_at: string
551+
readonly oauth_id: string
552+
readonly user_id: string
553+
}
554+
547555
// From codersdk/organizations.go
548556
export interface Organization {
549557
readonly id: string
@@ -1005,6 +1013,11 @@ export interface UpdateWorkspaceTTLRequest {
10051013
readonly ttl_ms?: number
10061014
}
10071015

1016+
// From codersdk/users.go
1017+
export interface UpgradeToOIDCRequest extends LoginWithPasswordRequest {
1018+
readonly oauth_provider: string
1019+
}
1020+
10081021
// From codersdk/files.go
10091022
export interface UploadResponse {
10101023
readonly hash: string

site/src/pages/UserSettingsPage/AccountPage/AccountPage.tsx

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ import { usePermissions } from "hooks/usePermissions"
77
import { SignInForm } from "components/SignInForm/SignInForm"
88
import { retrieveRedirect } from "utils/redirect"
99
import { useQuery } from "@tanstack/react-query"
10-
import { getAuthMethods } from "api/api"
10+
import { convertToOauth, getAuthMethods } from "api/api"
1111
import { AuthMethods } from "api/typesGenerated"
12+
import axios from "axios"
1213

1314
export const AccountPage: FC = () => {
1415
const queryKey = ["get-auth-methods"]
@@ -18,16 +19,16 @@ export const AccountPage: FC = () => {
1819
isLoading: authMethodsLoading,
1920
isFetched: authMethodsFetched,
2021
} = useQuery({
21-
select: (res: AuthMethods) => {
22-
return {
23-
...res,
24-
// Disable the password auth in this account section. For merging accounts,
25-
// we only want to support oidc.
26-
password: {
27-
enabled: false,
28-
},
29-
}
30-
},
22+
// select: (res: AuthMethods) => {
23+
// return {
24+
// ...res,
25+
// // Disable the password auth in this account section. For merging accounts,
26+
// // we only want to support oidc.
27+
// password: {
28+
// enabled: false,
29+
// },
30+
// }
31+
// },
3132
queryKey,
3233
queryFn: getAuthMethods,
3334
})
@@ -64,9 +65,29 @@ export const AccountPage: FC = () => {
6465
redirectTo={redirectTo}
6566
isSigningIn={false}
6667
error={authMethodsError}
67-
onSubmit={(credentials: { email: string; password: string }) => {
68-
console.log(credentials)
69-
return
68+
onSubmit={async (credentials: { email: string; password: string }) => {
69+
const mergeState = await convertToOauth(
70+
credentials.email,
71+
credentials.password,
72+
"oidc",
73+
)
74+
75+
window.location.href = `/api/v2/users/oidc/callback?oidc_merge_state=${
76+
mergeState?.state_string
77+
}&redirect=${encodeURIComponent(redirectTo)}`
78+
// await axios.get(
79+
// `/api/v2/users/oidc/callback?oidc_merge_state=${
80+
// mergeState?.state_string
81+
// }&redirect=${encodeURIComponent(redirectTo)}`,
82+
// )
83+
84+
{
85+
/* <Link
86+
href={`/api/v2/users/oidc/callback?redirect=${encodeURIComponent(
87+
redirectTo,
88+
)}`}
89+
> */
90+
}
7091
}}
7192
></SignInForm>
7293
</Section>

0 commit comments

Comments
 (0)