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

Allow account recovery for identities without email address #1419

Closed
andrewbanchich opened this issue Jun 14, 2021 · 16 comments
Closed

Allow account recovery for identities without email address #1419

andrewbanchich opened this issue Jun 14, 2021 · 16 comments
Labels
feat New feature or request. good first issue A good issue to tackle when being a novice to the project. help wanted We are looking for help on this one.

Comments

@andrewbanchich
Copy link
Contributor

For instances where identities don't require an email address, it would be useful to still allow account recovery. Since it's just a link, an admin could create it and send it to the user themselves.

@aeneasr
Copy link
Member

aeneasr commented Jun 14, 2021

@aeneasr aeneasr closed this as completed Jun 14, 2021
@andrewbanchich
Copy link
Contributor Author

andrewbanchich commented Jun 14, 2021

@aeneasr I may be misunderstanding something, but the docs you linked to show how to recover an account with an email address. The docs also say that is currently the only supported method:

The link method performs account recovery (also known as password reset) by sending an email containing a recovery link to the user.

@aeneasr
Copy link
Member

aeneasr commented Jun 14, 2021

Ah, my bad

@aeneasr aeneasr reopened this Jun 14, 2021
@aeneasr
Copy link
Member

aeneasr commented Jun 14, 2021

However, I believe it should work also if you don't have an email. It generates a link:

$ curl --request POST -sL \
    --header "Content-Type: application/json" \
    --request POST \
    --data '{
  "expires_in": "12h",
  "identity_id": "954f7f59-16a5-4152-8ce7-ad7c73bb124a"
}' \
    http://127.0.0.1:4434/recovery/link

{
  "expires_at": "2020-07-27T10:47:45.806Z",
  "recovery_link": "http://127.0.0.1:4433/self-service/browser/flows/recovery/link?request=8b6fd3e4-1de2-49bf-aa88-1a26634bf062\u0026token=b1tGmHf64cYDeHB9wKiuCF1FfycMJEyf"
}

Have you tried if this works?

@andrewbanchich
Copy link
Contributor Author

POST http://localhost:4434/identities

{
    "schema_id": "default",
    "traits": {
        "username": "test"
    }
}

GET http://localhost:4434/identities

[
    {
        "id": "36fe1677-83b6-4b44-87e3-c6dee4c2d160",
        "schema_id": "default",
        "schema_url": "https://mydomain.com/.ory/kratos/public/schemas/default",
        "traits": {
            "username": "test"
        }
    }
]

POST http://localhost:4434/recovery/link

{
  "expires_in": "12h",
  "identity_id": "36fe1677-83b6-4b44-87e3-c6dee4c2d160"
}

returns:

{
    "error": {
        "code": 400,
        "status": "Bad Request",
        "reason": "The identity does not have any recovery addresses set.",
        "message": "The request was malformed or contained invalid parameters"
    }
}

@aeneasr aeneasr added the feat New feature or request. label Jun 14, 2021
@aeneasr
Copy link
Member

aeneasr commented Jun 14, 2021

Ok, tracked as a feature :)

I believe we're currently making sure that recovery only really works when a recovery mechanism is in place for the user. However, it does make sense to skip this check for admins :)

@aeneasr aeneasr added this to the unplanned milestone Jun 14, 2021
@aeneasr aeneasr added help wanted We are looking for help on this one. good first issue A good issue to tackle when being a novice to the project. labels Jun 14, 2021
@andrewbanchich
Copy link
Contributor Author

Great, thanks!

@aeneasr aeneasr modified the milestones: unplanned, v0.8.0-alpha.1 Jun 15, 2021
@aeneasr
Copy link
Member

aeneasr commented Jun 15, 2021

There's a test case for this so if the test case is inverted I think that serves a good basis for implementation if anyone wants to tackle this:

t.Run("description=should not be able to recover an account that does not have a recovery email", func(t *testing.T) {
id := identity.Identity{Traits: identity.Traits(`{}`)}
require.NoError(t, reg.IdentityManager().Create(context.Background(),
&id, identity.ManagerAllowWriteProtectedTraits))
_, _, err := adminSDK.AdminApi.CreateRecoveryLink(context.Background()).CreateRecoveryLink(kratos.CreateRecoveryLink{
IdentityId: id.ID.String(),
}).Execute()
require.IsType(t, err, new(kratos.GenericOpenAPIError), "%T", err)
assert.EqualError(t, err.(*kratos.GenericOpenAPIError), "400 Bad Request")
})

Instead that should probably look more like this:

t.Run("description=should create a valid recovery link and set the expiry time and not be able to recover the account", func(t *testing.T) {
id := identity.Identity{Traits: identity.Traits(`{"email":"[email protected]"}`)}
require.NoError(t, reg.IdentityManager().Create(context.Background(),
&id, identity.ManagerAllowWriteProtectedTraits))
rl, _, err := adminSDK.AdminApi.CreateRecoveryLink(context.Background()).CreateRecoveryLink(kratos.CreateRecoveryLink{
IdentityId: id.ID.String(),
ExpiresIn: pointerx.String("100ms"),
}).Execute()
require.NoError(t, err)
time.Sleep(time.Millisecond * 100)
checkLink(t, rl, time.Now().Add(conf.SelfServiceFlowRecoveryRequestLifespan()))
res, err := publicTS.Client().Get(rl.RecoveryLink)
require.NoError(t, err)
require.Equal(t, http.StatusOK, res.StatusCode)
// We end up here because the link is expired.
assert.Contains(t, res.Request.URL.Path, "/recover", rl.RecoveryLink)
})

@morningvera
Copy link

hey @aeneasr, i'm interested in giving this a shot if no one else is working on it yet!

@aeneasr
Copy link
Member

aeneasr commented Jun 24, 2021

That would be awesome! :) As far as I know noone's working on it right now

@dibyajyotibehera
Copy link
Contributor

i can check this , if not already worked on

@dibyajyotibehera
Copy link
Contributor

@aeneasr Looks like the /recovery/link endpoint is open on public port also (redirect to admin port). code here .

Should this endpoint not be blocked on public port since the use case for this api is for admin to invite new users .

func (s *Strategy) RegisterPublicRecoveryRoutes(public *x.RouterPublic) {
	s.d.CSRFHandler().IgnorePath(RouteAdminCreateRecoveryLink)
	public.POST(RouteAdminCreateRecoveryLink, x.RedirectToAdminRoute(s.d))

}

@aeneasr
Copy link
Member

aeneasr commented Aug 21, 2021

It is expected for the admin port to be protected. The redirect helps if one confused the port, for example during development.

dibyajyotibehera added a commit to dibyajyotibehera/kratos that referenced this issue Aug 25, 2021
dibyajyotibehera added a commit to dibyajyotibehera/kratos that referenced this issue Aug 25, 2021
@abador
Copy link
Contributor

abador commented Sep 2, 2021

@dibyajyotibehera are you still on this issue? Maybe I could help somehow?

@dibyajyotibehera
Copy link
Contributor

dibyajyotibehera commented Sep 2, 2021

@abador - edit - no i am not working on it now. there is a slack thread you might want to check- https://ory-community.slack.com/archives/C012USDT5QQ/p1629889562018400 . Had some ideas but not sure if thats the right way to move forward.

@abador
Copy link
Contributor

abador commented Sep 14, 2021

@aeneasr @dibyajyotibehera I needed to run migrations-replace or the errors prevented the script from finishing. Sorry it took so long :)

abador added a commit to Wikia/kratos that referenced this issue Sep 15, 2021
abador added a commit to Wikia/kratos that referenced this issue Sep 15, 2021
abador added a commit to Wikia/kratos that referenced this issue Sep 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat New feature or request. good first issue A good issue to tackle when being a novice to the project. help wanted We are looking for help on this one.
Projects
None yet
Development

No branches or pull requests

5 participants