dazzling-honey-93005
10/14/2022, 6:33 PMreturn_to
param set to loginchallelnge generate by hydra, the login flow is not as expected,
Were as if I hit the endpoint localhost:4433/self-service/login/browser
I get the appropriate response (second image),
I also checked the response of /self-service/login/flows?id=<flowid>
I get 403
Unauthorised access error.
been referencing https://github.com/atreya2011/go-kratos-test/tree/hydrabulky-architect-22083
10/15/2022, 12:58 AMhydra-consent
branch and use the code in that branch. The README in that branch is up to date to get everything up and running 🙏🏼dazzling-honey-93005
10/15/2022, 3:16 AMhydra
and hydra-consent
branch is not different ig.bulky-architect-22083
10/15/2022, 3:19 AMdazzling-honey-93005
10/15/2022, 3:20 AMbulky-architect-22083
10/15/2022, 3:21 AMdazzling-honey-93005
10/15/2022, 3:27 AMHandleLogin
handler in the example code,
What happens is login challenge is created and then login flow is created, I get the flowID
and then I call GetSelfServiceLoginFlow
which will contain all the UI attributes to populate the form, but it is empty.
If the flowID is generated correctly, how ``GetSelfServiceLoginFlow`` returns wrong response.
I can confirm identity schema
is not malformed, as when I explicitly call localhost:4433/self-service/login/browser
I get the correct formbulky-architect-22083
10/15/2022, 3:30 AMdazzling-honey-93005
10/15/2022, 4:05 AMhydra-dev:
(docker rm -f ory-hydra) || true
docker run -it --rm \
--network meshery-net \
oryd/hydra:v1.3.2 \
migrate sql --yes $(DEV_DB_URL_HYDRA)
docker run -d \
--network meshery-net \
--name ory-hydra \
-p $(DEV_HYDRA_PORT_ADMIN):4445 \
-p $(DEV_HYDRA_PORT_PUBLIC):4444 \
-e DEV_SECRETS_SYSTEM=$(DEV_SECRETS_SYSTEM) \
-e DSN=$(DEV_DB_URL_HYDRA) \
-e URLS_SELF_ISSUER=$(DEV_HYDRA_PUBLIC) \
-e URLS_CONSENT=$(DEV_SERVER_BASE_URL)/consent \
-e URLS_LOGIN=$(DEV_SERVER_BASE_URL)/login \
-e OAUTH2_ERROR_URL=$(DEV_SERVER_BASE_URL)/error \
-e OAUTH2_ACCESS_TOKEN_STRATEGY=jwt \
-e TTL_ACCESS_TOKEN=$(DEV_TTL_ACCESS_TOKEN) \
-e TTL_REFRESH_TOKEN=$(DEV_TTL_REFRESH_TOKEN) \
oryd/hydra:v1.3.2 serve all --dangerous-force-http
docker run --rm -it \
--network meshery-net \
-e HYDRA_ADMIN_URL=<http://ory-hydra:4445> \
oryd/hydra:v1.3.2 \
clients create \
--id $(DEV_OAUTH2_CLIENT_ID) \
--secret $(DEV_OAUTH2_SECRET) \
--grant-types authorization_code,refresh_token,client_credentials,implicit \
--response-types token,code,id_token \
--scope openid,offline,offline_access \
--callbacks $(DEV_SERVER_BASE_URL)/callback
kratos config:
version: v0.10.1
dsn: <postgres://postgres:postgres@postgres:5432/kratos?sslmode=disable>
serve:
public:
base_url: <http://127.0.0.1:9010/>
cors:
enabled: true
admin:
base_url: <http://127.0.0.1:9011/>
selfservice:
default_browser_return_url: <http://127.0.0.1:9876/>
allowed_return_urls:
- <http://127.0.0.1:9876>
methods:
password:
enabled: true
link:
enabled: true
config:
lifespan: 15m
flows:
error:
ui_url: <http://127.0.0.1:9876/error>
settings:
ui_url: <http://127.0.0.1:9876/settings>
privileged_session_max_age: 15m
recovery:
enabled: true
ui_url: <http://127.0.0.1:9876/recovery>
verification:
enabled: true
ui_url: <http://127.0.0.1:9876/verification>
after:
default_browser_return_url: <http://127.0.0.1:9876/>
lifespan: 15m
logout:
after:
default_browser_return_url: <http://127.0.0.1:9876/login>
login:
ui_url: <http://127.0.0.1:9876/login>
lifespan: 10m
registration:
lifespan: 10m
ui_url: <http://127.0.0.1:9876/registration>
after:
password:
hooks:
- hook: session
oidc:
hooks:
- hook: session
log:
level: debug
format: text
leak_sensitive_values: true
secrets:
cookie:
- qwertyuiop
cipher:
- qwertyiplkjhgfdsxcvbbn
ciphers:
algorithm: xchacha20-poly1305
hashers:
argon2:
parallelism: 1
memory: 128MB
iterations: 2
salt_length: 16
key_length: 16
identity:
schemas:
- id: default
url: file:///home/ory/identity.schema.json
default_schema_id: "default"
courier:
smtp:
connection_uri: <smtps://test:test@mailslurper:1025/?skip_ssl_verify=true>
oauth config when starting the server:
&oauth2.Config{
ClientID: viper.GetString("OAUTH2_CLIENT_ID"),
ClientSecret: viper.GetString("OAUTH2_SECRET"),
Endpoint: oauth2.Endpoint{
TokenURL: viper.GetString("HYDRA_PUBLIC") + "/oauth2/token",
AuthURL: viper.GetString("HYDRA_PUBLIC") + "/oauth2/auth",
// AuthStyle: oauth2.AuthStyleInHeader,
},
RedirectURL: redirectURL,
Scopes: []string{"openid", "offline", "offline_access"},
},
handler for /login
:
func (h *Handlers) HandleLogin(w http.ResponseWriter, r *http.Request) {
// h.PerformLogin()
loginChal := r.URL.Query().Get("login_challenge")
flowID := r.URL.Query().Get("flow")
// redirect to login if there is no login challenge or flow
if loginChal == "" && flowID == "" {
log.Println("No login challenge found or flow ID")
st := make([]byte, 32)
_, err := rand.Read(st)
if err != nil {
logrus.Error("generate state failed: %v", err)
return
}
state := base64.StdEncoding.EncodeToString(st)
setSessionValue(w, r, "oauth2State", state)
// start oauth2 authorization code flow
redirectTo := h.OAuth2Config.AuthCodeURL(state)
logrus.Infof("redirect to hydra, url: %s", redirectTo)
http.Redirect(w, r, redirectTo, http.StatusFound)
return
}
var metadata Metadata
// get login request from hydra only if there is no flow id in the url query parameters
if flowID == "" {
loginRes, _, err := h.HydraCl.HydraAPIClient.AdminApi.GetLoginRequest(r.Context()).LoginChallenge(loginChal).Execute()
if err != nil {
logrus.Error(err)
writeError(w, http.StatusUnauthorized, errors.New("Unauthorized OAuth Client"))
return
}
log.Println("got client id: ", loginRes.Client.ClientId)
// client details from hydra
clientRes, _, err := h.HydraCl.HydraAPIClient.AdminApi.GetOAuth2Client(r.Context(), *loginRes.Client.ClientId).Execute()
if err != nil {
logrus.Error(err)
writeError(w, http.StatusUnauthorized, errors.New("Unauthorized OAuth Client"))
return
}
log.Println("got client metadata: ", clientRes.Metadata)
// convert map to json string
md, err := json.Marshal(clientRes.Metadata)
if err != nil {
logrus.Error(err)
writeError(w, http.StatusInternalServerError, errors.New("Unable to marshal metadata"))
return
}
// convert json string to struct
if err = json.Unmarshal([]byte(md), &metadata); err != nil {
logrus.Error(err)
writeError(w, http.StatusInternalServerError, errors.New("Internal Server Error"))
return
}
}
// store metadata value in session
v := getSessionValue(w, r, "canRegister")
reg, ok := v.(bool)
if ok {
metadata.Registration = reg
} else {
setSessionValue(w, r, "canRegister", metadata.Registration)
}
cookie := r.Header.Get("cookie")
// check for kratos session details
session, _, err := h.KratosCl.APIClient.V0alpha2Api.ToSession(r.Context()).Cookie(cookie).Execute()
// if there is no session, redirect to login page with login challenge
if err != nil {
// build return_to url with hydra login challenge as url query parameter
returnToParams := url.Values{
"login_challenge": []string{loginChal},
}
returnTo := "/login?" + returnToParams.Encode()
// build redirect url with return_to as url query parameter
// refresh=true forces a new login from kratos regardless of browser sessions
// this is important because we are letting Hydra handle sessions
redirectToParam := url.Values{
"return_to": []string{returnTo},
"refresh": []string{"true"},
}
redirectTo := fmt.Sprintf("%s/self-service/login/browser?", h.KratosCl.KratosPublicURL) + redirectToParam.Encode()
// get flowID from url query parameters
flowID := r.URL.Query().Get("flow")
logrus.Infof("FLOW_ID: %s", flowID)
// if there is no flow id in url query parameters, create a new flow
if flowID == "" {
http.Redirect(w, r, redirectTo, http.StatusFound)
return
}
// get cookie from headers
cookie := r.Header.Get("cookie")
// get the login flow
flow, _, err := h.KratosCl.APIClient.V0alpha2Api.GetSelfServiceLoginFlow(r.Context()).Id(flowID).Cookie(cookie).Execute()
if err != nil {
writeError(w, http.StatusUnauthorized, err)
return
}
templateData := templateData{
Title: "Login",
UI: &flow.Ui,
Metadata: metadata,
}
// render template index.html
templateData.Render(w, "loginpassword.html")
return
}
// if there is a valid session, marshal session.identity.traits to json to be stored in subject
traitsJSON, err := json.Marshal(session.Identity.Traits)
if err != nil {
writeError(w, http.StatusInternalServerError, err)
return
}
subject := string(traitsJSON)
hydraReq := models.HydraLoginRequest{
Remember: false,
RememberFor: 0,
Subject: subject,
}
// accept hydra login request
redirectURL, err := h.HydraCl.AcceptLoginRequest(&hydraReq, loginChal)
if err != nil {
logrus.Error(err)
writeError(w, http.StatusUnauthorized, errors.New("Unauthorized OAuth Client"))
return
}
http.Redirect(w, r, redirectURL, http.StatusFound)
}
I can’t point you to a repo due to restrictions, I have provided necessary snippets, do tell if anything more is required.dazzling-honey-93005
10/15/2022, 9:51 AMERRO[0018] 401 Unauthorized
{
"created_at": "2022-10-15T09:40:13.549878Z",
"expires_at": "2022-10-15T09:50:13.544491Z",
"id": "e201e674-732a-4102-a2c3-7f41c9d6ffc3",
"issued_at": "2022-10-15T09:40:13.544491Z",
"refresh": true,
"request_url": "<http://127.0.0.1:9010/self-service/login/browser?refresh=true>\u0026return_to=%2Flogin%3Flogin_challenge%3D5339b74418e14dcd9a9bf27617887d1a",
"requested_aal": "aal1",
"return_to": "/login?login_challenge=5339b74418e14dcd9a9bf27617887d1a",
"type": "browser",
"ui": {
"action": "<http://127.0.0.1:9010/self-service/login?flow=e201e674-732a-4102-a2c3-7f41c9d6ffc3>",
"messages": [
{
"context": {},
"id": 1010003,
"text": "Please confirm this action by verifying that it is you.",
"type": "info"
}
],
"method": "POST",
"nodes": [
{
"attributes": {
"disabled": false,
"name": "provider",
"node_type": "input",
"type": "submit",
"value": "github"
},
"group": "oidc",
"messages": [],
"meta": {
"label": {
"context": {
"provider": "github"
},
"id": 1010002,
"text": "Sign in with github",
"type": "info"
}
},
"type": "input"
},
{
"attributes": {
"disabled": false,
"name": "csrf_token",
"node_type": "input",
"required": true,
"type": "hidden",
"value": "GkX+v5//hMAJ5CEj8FU0sqGqfLp26Glc88iz+jz5/vgsoGFTxxLBnpIxBkGnZKKCCRHa2Ym3VrpHDZvqhoS/zA=="
},
"group": "default",
"messages": [],
"meta": {},
"type": "input"
}
]
},
"updated_at": "2022-10-15T09:40:13.549878Z"
}
When I do GetSelfServiceLoginFlow
above o/p I am getting, only the OIDC method works, password method is not working. // @bulky-architect-22083