Преглед изворни кода

all auth tests passing again

tags/v0.1.6
Jonathan Cobb пре 4 година
родитељ
комит
8ff98c9609
8 измењених фајлова са 151 додато и 74 уклоњено
  1. +2
    -1
      bubble-server/src/main/java/bubble/model/account/AccountContact.java
  2. +6
    -1
      bubble-server/src/main/java/bubble/model/account/AuthenticatorRequest.java
  3. +13
    -1
      bubble-server/src/main/java/bubble/resources/account/AccountsResource.java
  4. +3
    -1
      bubble-server/src/main/java/bubble/resources/account/AuthResource.java
  5. +1
    -0
      bubble-server/src/main/java/bubble/service/account/StandardAccountMessageService.java
  6. +28
    -9
      bubble-server/src/test/resources/models/tests/auth/forgot_password.json
  7. +97
    -60
      bubble-server/src/test/resources/models/tests/auth/multifactor_auth.json
  8. +1
    -1
      bubble-web

+ 2
- 1
bubble-server/src/main/java/bubble/model/account/AccountContact.java Прегледај датотеку

@@ -54,6 +54,7 @@ public class AccountContact implements Serializable {
@HasValue(message="err.info.required")
@Getter @Setter private String info;

@JsonIgnore public String getTotpKey () { return totpInfo().getKey(); }
public TotpBean totpInfo () { return !empty(info) && isAuthenticator() ? json(info, TotpBean.class) : null; }

@HasValue(message="err.cloudServiceType.required")
@@ -93,7 +94,7 @@ public class AccountContact implements Serializable {

if (c.isAuthenticator()) {
final AccountContact auth = findAuthenticator(contacts);
if (auth != null && !auth.getUuid().equals(c.getUuid())) {
if (auth != null && (!c.hasUuid() || !auth.getUuid().equals(c.getUuid()))) {
throw invalidEx("err.authenticator.configured", "Only one authenticator can be configured");
}
}


+ 6
- 1
bubble-server/src/main/java/bubble/model/account/AuthenticatorRequest.java Прегледај датотеку

@@ -5,11 +5,16 @@ import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;

import static org.cobbzilla.util.string.StringUtil.safeParseInt;

@NoArgsConstructor @Accessors(chain=true)
public class AuthenticatorRequest {

@Getter @Setter private String account;
@Getter @Setter private int token;

@Getter @Setter private String token;
public Integer intToken() { return safeParseInt(getToken()); }

@Getter @Setter private Boolean verify;
public boolean verify() { return verify != null && verify; }



+ 13
- 1
bubble-server/src/main/java/bubble/resources/account/AccountsResource.java Прегледај датотеку

@@ -148,7 +148,9 @@ public class AccountsResource {

final AccountContact existing = policy.findContact(contact);
if (existing != null) {
if (existing.isAuthenticator()) return invalid("err.authenticator.configured");
if (existing.isAuthenticator() && (!contact.hasUuid() || !existing.getUuid().equals(contact.getUuid()))) {
return invalid("err.authenticator.configured");
}

// if it already exists, these fields cannot be changed
contact.setUuid(existing.getUuid());
@@ -210,6 +212,16 @@ public class AccountsResource {
return ok(policyDAO.update(policy.removeContact(contact)).mask());
}

@DELETE @Path("/{id}"+EP_POLICY+EP_CONTACTS+EP_AUTHENTICATOR)
public Response removeAuthenticator(@Context ContainerRequest ctx,
@PathParam("id") String id) {
final AccountContext c = new AccountContext(ctx, id);
final AccountPolicy policy = policyDAO.findSingleByAccount(c.account.getUuid());
final AccountContact contact = policy.findContact(new AccountContact().setType(CloudServiceType.authenticator));
if (contact == null) return notFound(CloudServiceType.authenticator.name());
return ok(policyDAO.update(policy.removeContact(contact)).mask());
}

@DELETE @Path("/{id}"+EP_POLICY+EP_CONTACTS+"/{uuid}")
public Response removeContactByUuid(@Context ContainerRequest ctx,
@PathParam("id") String id,


+ 3
- 1
bubble-server/src/main/java/bubble/resources/account/AuthResource.java Прегледај датотеку

@@ -300,7 +300,9 @@ public class AuthResource {
if (authenticator == null) return invalid("err.authenticator.notConfigured");

final String secret = authenticator.totpInfo().getKey();
if (G_AUTH.authorize(secret, request.getToken())) {
final Integer code = request.intToken();
if (code == null) return invalid("err.token.invalid");
if (G_AUTH.authorize(secret, code)) {
if (request.verify()) {
policyDAO.update(policy.verifyContact(policy.getAuthenticator().getUuid()));
return ok_empty();


+ 1
- 0
bubble-server/src/main/java/bubble/service/account/StandardAccountMessageService.java Прегледај датотеку

@@ -197,6 +197,7 @@ public class StandardAccountMessageService implements AccountMessageService {
AccountMessageType type) {
return captureResponse(account, remoteHost, token, type, null);
}

public AccountMessage captureResponse(Account account,
String remoteHost,
String token,


+ 28
- 9
bubble-server/src/test/resources/models/tests/auth/forgot_password.json Прегледај датотеку

@@ -3,6 +3,8 @@
"comment": "activate service, create account, login",
"include": "new_account",
"params": {
"username": "user-forgot_password",
"email": "user-forgot_password@example.com",
"password": "foobar",
"verifyEmail": "true"
}
@@ -17,6 +19,18 @@
"info": "US:800-555-1212"
}
},
"response": {
"store": "policy",
"check": [
{"condition": "json.getType().name() == 'sms'"},
{"condition": "json.getInfo() == 'US:800-555-1212'"}
]
}
},

{
"comment": "re-read user policy",
"request": { "uri": "users/{{userAccount.name}}/policy" },
"response": {
"store": "policy",
"check": [
@@ -48,11 +62,7 @@
"request": {
"session": "userSession",
"uri": "auth/approve/{{smsInbox.[0].ctx.confirmationToken}}",
"method": "post"
},
"response": {
"sessionName": "userSession",
"session": "token"
"entity": [{"name": "account", "value": "user-forgot_password"}]
}
},

@@ -74,7 +84,7 @@
"comment": "as root, check email inbox, expect reset password request",
"request": {
"session": "rootSession",
"uri": "debug/inbox/email/{{policy.firstEmail}}?action=password"
"uri": "debug/inbox/email/user-forgot_password@example.com?action=password"
},
"response": {
"store": "emailInbox",
@@ -109,7 +119,10 @@
"request": {
"session": "new",
"uri": "auth/approve/{{emailInbox.[0].ctx.confirmationToken}}",
"entity": [{ "name": "password", "value": "new_password" }]
"entity": [
{ "name": "account", "value": "user-forgot_password" },
{ "name": "password", "value": "new_password" }
]
},
"response": {
"status": 422,
@@ -122,7 +135,10 @@
"request": {
"session": "new",
"uri": "auth/approve/{{emailInbox.[0].ctx.confirmationToken}}",
"entity": [{ "name": "password", "value": "new_password1!" }]
"entity": [
{ "name": "account", "value": "user-forgot_password" },
{ "name": "password", "value": "new_password1!" }
]
}
},

@@ -131,7 +147,10 @@
"request": {
"session": "new",
"uri": "auth/approve/{{smsInbox.[0].ctx.confirmationToken}}",
"entity": [{ "name": "password", "value": "another_new_password1!" }]
"entity": [
{ "name": "account", "value": "user-forgot_password" },
{ "name": "password", "value": "another_new_password1!" }
]
},
"response": {
"status": 422,


+ 97
- 60
bubble-server/src/test/resources/models/tests/auth/multifactor_auth.json Прегледај датотеку

@@ -3,6 +3,8 @@
"comment": "activate service, create account, login",
"include": "new_account",
"params": {
"username": "user-multifactor_auth",
"email": "user-multifactor_auth@example.com",
"password": "foobar1!"
}
},
@@ -27,7 +29,7 @@
"uri": "users/{{userAccount.name}}/policy/contacts",
"entity": {
"type": "email",
"info": "{{policy.firstEmail}}",
"info": "user-multifactor_auth@example.com",
"authFactor": "required"
}
},
@@ -45,7 +47,7 @@
"uri": "users/{{userAccount.name}}/policy/contacts/verify",
"entity": {
"type": "email",
"info": "{{policy.firstEmail}}"
"info": "user-multifactor_auth@example.com"
}
}
},
@@ -55,7 +57,7 @@
"comment": "as root, check inbox (1st) for email verification message",
"request": {
"session": "rootSession",
"uri": "debug/inbox/email/{{policy.firstEmail}}?action=verify"
"uri": "debug/inbox/email/user-multifactor_auth@example.com?action=verify"
},
"response": {
"store": "userInbox",
@@ -72,11 +74,7 @@
"request": {
"session": "userSession",
"uri": "auth/approve/{{userInbox.[0].ctx.confirmationToken}}",
"method": "post"
},
"response": {
"sessionName": "userSession",
"session": "token"
"entity": [{"name": "account", "value": "user-multifactor_auth"}]
}
},

@@ -102,10 +100,22 @@
"uri": "users/{{userAccount.name}}/policy/contacts",
"entity": {
"type": "email",
"info": "{{policy.firstEmail}}",
"info": "user-multifactor_auth@example.com",
"authFactor": "required"
}
},
"response": {
"check": [
{"condition": "json.getType().name() == 'email'"},
{"condition": "json.getInfo() == 'user-multifactor_auth@example.com'"},
{"condition": "json.getAuthFactor().name() == 'required'"}
]
}
},

{
"comment": "re-read policy, verify email is now a required auth factor",
"request": { "uri": "users/{{userAccount.name}}/policy" },
"response": {
"store": "policy",
"check": [
@@ -135,6 +145,7 @@
"check": [
{"condition": "json.getMultifactorAuth() != null"},
{"condition": "json.getMultifactorAuth().length == 1"},
{"condition": "json.getMultifactorAuth()[0].getType().name() == 'email'"},
{"condition": "json.getMultifactorAuth()[0].getInfo().indexOf('***') != -1"}
]
}
@@ -145,7 +156,7 @@
"comment": "as root, check inbox (2nd), verify login request message sent",
"request": {
"session": "rootSession",
"uri": "debug/inbox/email/{{policy.firstEmail}}?action=login"
"uri": "debug/inbox/email/user-multifactor_auth@example.com?action=login"
},
"response": {
"store": "userInbox",
@@ -162,7 +173,7 @@
"request": {
"session": "userSession",
"uri": "auth/approve/{{userInbox.[0].ctx.confirmationToken}}",
"method": "post"
"entity": [{"name": "account", "value": "user-multifactor_auth"}]
},
"response": {
"sessionName": "userSession",
@@ -178,6 +189,46 @@
"type": "authenticator"
}
},
"response": {
"store": "authenticator",
"check": [
{"condition": "json.getType().name() == 'authenticator'"}
]
}
},

{
"comment": "verify authenticator",
"request": {
"uri": "auth/authenticator",
"entity": {
"account": "{{userAccount.name}}",
"token": "{{authenticator_token authenticator.totpKey}}",
"verify": true
}
}
},

{
"comment": "set authenticator as required auth factor",
"request": {
"uri": "users/{{userAccount.name}}/policy/contacts",
"data": "authenticator",
"entity": {
"authFactor": "required"
}
},
"response": {
"store": "authenticator",
"check": [
{"condition": "json.getType().name() == 'authenticator'"}
]
}
},

{
"comment": "re-read policy, both contacts are now required auth factors",
"request": { "uri": "users/{{userAccount.name}}/policy" },
"response": {
"store": "policy",
"check": [
@@ -209,7 +260,7 @@
{"condition": "json.getMultifactorAuth() != null"},
{"condition": "json.getMultifactorAuth().length == 2"},
{"condition": "json.getMultifactorAuth()[0].getInfo().indexOf('***') != -1"},
{"condition": "json.getMultifactorAuth()[1].getInfo().indexOf('***') != -1"}
{"condition": "json.getMultifactorAuth()[1].getInfo() == '{\"masked\": true}'"}
]
}
},
@@ -219,7 +270,7 @@
"comment": "as root, check inbox (3rd), verify login request message sent",
"request": {
"session": "rootSession",
"uri": "debug/inbox/email/{{policy.firstEmail}}?action=login"
"uri": "debug/inbox/email/user-multifactor_auth@example.com?action=login"
},
"response": {
"store": "userInbox",
@@ -236,7 +287,7 @@
"request": {
"session": "userSession",
"uri": "auth/approve/{{userInbox.[0].ctx.confirmationToken}}",
"method": "post"
"entity": [{"name": "account", "value": "user-multifactor_auth"}]
},
"response": {
"store": "remainingApprovals",
@@ -244,7 +295,7 @@
{"condition": "json.getUuid() == null"},
{"condition": "json.getMultifactorAuth() != null"},
{"condition": "json.getMultifactorAuth().length == 1"},
{"condition": "json.getMultifactorAuth()[0].getInfo().indexOf('***') != -1"}
{"condition": "json.getMultifactorAuth()[0].getInfo() == '{\"masked\": true}'"}
]
}
},
@@ -255,7 +306,7 @@
"uri": "auth/authenticator",
"entity": {
"account": "{{userAccount.name}}",
"token": "{{authenticator_token policy.authenticator.info}}"
"token": "{{authenticator_token authenticator.totpKey}}"
}
},
"response": {
@@ -265,9 +316,9 @@
},

{
"comment": "remove email as required auth factor",
"comment": "remove email from contacts",
"request": {
"uri": "users/{{userAccount.name}}/policy/contacts/email/{{policy.firstEmail}}",
"uri": "users/{{userAccount.name}}/policy/contacts/email/user-multifactor_auth@example.com",
"method": "delete"
},
"response": {
@@ -308,10 +359,10 @@
}
},
"response": {
"store": "policy",
"store": "smsContact",
"check": [
{"condition": "json.getAccountContacts() != null"},
{"condition": "json.getAccountContacts().length == 2"}
{"condition": "json.getType().name() == 'sms'"},
{"condition": "json.getAuthFactor().name() == 'not_required'"}
]
}
},
@@ -338,11 +389,7 @@
"request": {
"session": "userSession",
"uri": "auth/approve/{{smsInbox.[0].ctx.confirmationToken}}",
"method": "post"
},
"response": {
"sessionName": "userSession",
"session": "token"
"entity": [{"name": "account", "value": "user-multifactor_auth"}]
}
},

@@ -369,17 +416,14 @@
"uri": "users/{{userAccount.name}}/policy/contacts",
"entity": {
"type": "sms",
"info": "{{policy.firstSms}}",
"info": "{{smsContact.info}}",
"authFactor": "sufficient"
}
},
"response": {
"store": "policy",
"check": [
{"condition": "json.getAccountContacts() != null"},
{"condition": "json.getAccountContacts().length == 2"},
{"condition": "json.getAccountContacts()[1].sufficientAuthFactor()"},
{"condition": "json.getAccountContacts()[1].getType().name() == 'sms'"}
{"condition": "json.getType().name() == 'sms'"},
{"condition": "json.getAuthFactor().name() == 'sufficient'"}
]
}
},
@@ -404,7 +448,7 @@
"check": [
{"condition": "json.getMultifactorAuth() != null"},
{"condition": "json.getMultifactorAuth().length == 2"},
{"condition": "json.getMultifactorAuth()[0].getInfo().indexOf('***') != -1"},
{"condition": "json.getMultifactorAuth()[0].getInfo() == '{\"masked\": true}'"},
{"condition": "json.getMultifactorAuth()[1].getInfo().indexOf('***') != -1"}
]
}
@@ -432,7 +476,7 @@
"request": {
"session": "userSession",
"uri": "auth/approve/{{smsInbox.[0].ctx.confirmationToken}}",
"method": "post"
"entity": [{"name": "account", "value": "user-multifactor_auth"}]
},
"response": {
"store": "remainingApprovals",
@@ -440,7 +484,7 @@
{"condition": "json.getUuid() == null"},
{"condition": "json.getMultifactorAuth() != null"},
{"condition": "json.getMultifactorAuth().length == 1"},
{"condition": "json.getMultifactorAuth()[0].getInfo().indexOf('***') != -1"}
{"condition": "json.getMultifactorAuth()[0].getInfo() == '{\"masked\": true}'"}
]
}
},
@@ -451,7 +495,7 @@
"uri": "auth/authenticator",
"entity": {
"account": "{{userAccount.name}}",
"token": "{{authenticator_token policy.authenticator.info}}"
"token": "{{authenticator_token authenticator.totpKey}}"
}
},
"response": {
@@ -461,7 +505,7 @@
},

{
"comment": "remove authenticator",
"comment": "remove authenticator, only SMS remains as contact method",
"request": {
"uri": "users/{{userAccount.name}}/policy/contacts/authenticator",
"method": "delete"
@@ -470,7 +514,8 @@
"store": "policy",
"check": [
{"condition": "json.getAccountContacts() != null"},
{"condition": "json.getAccountContacts().length == 1"}
{"condition": "json.getAccountContacts().length == 1"},
{"condition": "json.getAccountContacts()[0].getType().name() == 'sms'"}
]
}
},
@@ -485,10 +530,9 @@
}
},
"response": {
"store": "policy",
"check": [
{"condition": "json.getAccountContacts() != null"},
{"condition": "json.getAccountContacts().length == 2"}
{"condition": "json.getType().name() == 'email'"},
{"condition": "json.getInfo() == 'foo@example.com'"}
]
}
},
@@ -515,11 +559,7 @@
"request": {
"session": "userSession",
"uri": "auth/approve/{{userInbox.[0].ctx.confirmationToken}}",
"method": "post"
},
"response": {
"sessionName": "userSession",
"session": "token"
"entity": [{"name": "account", "value": "user-multifactor_auth"}]
}
},

@@ -535,10 +575,9 @@
}
},
"response": {
"store": "policy",
"check": [
{"condition": "json.getAccountContacts() != null"},
{"condition": "json.getAccountContacts().length == 2"}
{"condition": "json.getAuthFactor().name() == 'sufficient'"},
{"condition": "json.getInfo() == 'foo@example.com'"}
]
}
},
@@ -573,7 +612,7 @@
"comment": "as root, check inbox (7th), verify login request message sent",
"request": {
"session": "rootSession",
"uri": "debug/inbox/email/{{policy.firstEmail}}?action=login"
"uri": "debug/inbox/email/foo@example.com?type=request&action=login&target=account"
},
"response": {
"store": "userInbox",
@@ -590,7 +629,7 @@
"request": {
"session": "userSession",
"uri": "auth/approve/{{userInbox.[0].ctx.confirmationToken}}",
"method": "post"
"entity": [{"name": "account", "value": "user-multifactor_auth"}]
},
"response": {
"sessionName": "userSession",
@@ -609,10 +648,9 @@
}
},
"response": {
"store": "policy",
"check": [
{"condition": "json.getAccountContacts() != null"},
{"condition": "json.getAccountContacts().length == 2"}
{"condition": "json.getType().name() == 'email'"},
{"condition": "json.getAuthFactor().name() == 'not_required'"}
]
}
},
@@ -623,15 +661,14 @@
"uri": "users/{{userAccount.name}}/policy/contacts",
"entity": {
"type": "sms",
"info": "US:800-555-1212",
"info": "{{smsContact.info}}",
"authFactor": "not_required"
}
},
"response": {
"store": "policy",
"check": [
{"condition": "json.getAccountContacts() != null"},
{"condition": "json.getAccountContacts().length == 2"}
{"condition": "json.getType().name() == 'sms'"},
{"condition": "json.getAuthFactor().name() == 'not_required'"}
]
}
},
@@ -669,8 +706,8 @@
"response": {
"store": "policy",
"check": [
{"condition": "json.getAccountContacts() != null"},
{"condition": "json.getAccountContacts().length == 3"}
{"condition": "json.getInfo() == 'bar@example.com'"},
{"condition": "json.getType().name() == 'email'"}
]
}
},


+ 1
- 1
bubble-web

@@ -1 +1 @@
Subproject commit 2d43a115e364e3c886dfde195339572eb079880e
Subproject commit 8ccb01dd1484e42243ecf2598c2b8c257fec1b9b

Loading…
Откажи
Сачувај