Browse Source

WIP. more api work

tags/v1.4.37
Jonathan Cobb 4 years ago
parent
commit
32ecf2fc1b
6 changed files with 76 additions and 33 deletions
  1. +4
    -4
      bubble-server/src/main/java/bubble/resources/account/AccountOwnedResource.java
  2. +7
    -7
      bubble-server/src/main/java/bubble/resources/account/AccountsResource.java
  3. +17
    -16
      bubble-server/src/main/java/bubble/resources/account/AuthResource.java
  4. +46
    -4
      bubble-server/src/main/java/bubble/resources/account/MeResource.java
  5. +1
    -1
      utils/cobbzilla-utils
  6. +1
    -1
      utils/cobbzilla-wizard

+ 4
- 4
bubble-server/src/main/java/bubble/resources/account/AccountOwnedResource.java View File

@@ -171,10 +171,10 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT_OBJECTS},
summary="Create a new object",
description="Create a new object. If validation errors occur, status "+SC_PRECONDITION_FAILED+" is returned and the response will contain an array of errors. Within each error, the `messageTemplate` field refers to messages that can be localized using the /messages resource",
description="Create a new object. If validation errors occur, status "+SC_INVALID+" is returned and the response will contain an array of errors. Within each error, the `messageTemplate` field refers to messages that can be localized using the /messages resource",
responses={
@ApiResponse(responseCode=SC_OK, description="the object that was created"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred",
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]")
})})
@@ -212,12 +212,12 @@ public class AccountOwnedResource<E extends HasAccount, DAO extends AccountOwned
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT_OBJECTS},
summary="Update an existing object",
description="Update an new object. For many types, the object will be created if it does not exist. If validation errors occur, status "+SC_PRECONDITION_FAILED+" is returned and the response will contain an array of errors. Within each error, the `messageTemplate` field refers to messages that can be localized using the /messages resource",
description="Update an new object. For many types, the object will be created if it does not exist. If validation errors occur, status "+SC_INVALID+" is returned and the response will contain an array of errors. Within each error, the `messageTemplate` field refers to messages that can be localized using the /messages resource",
parameters={@Parameter(name="id", description="the UUID (or name, if allowed) of the object to update")},
responses={
@ApiResponse(responseCode=SC_OK, description="the object that was updated"),
@ApiResponse(responseCode=SC_NOT_FOUND, description="no object exists with the given id"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred",
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred",
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="validation errors", value="[{\"messageTemplate\": \"some.symbolic.error\", \"message\": \"some default English message\"}]")
})})


+ 7
- 7
bubble-server/src/main/java/bubble/resources/account/AccountsResource.java View File

@@ -203,7 +203,7 @@ public class AccountsResource {
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is updating any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response updateUser(@Context ContainerRequest ctx,
@@ -282,7 +282,7 @@ public class AccountsResource {
responses={
@ApiResponse(responseCode=SC_OK, description="an AccountPolicy object"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response updatePolicy(@Context ContainerRequest ctx,
@@ -312,7 +312,7 @@ public class AccountsResource {
responses={
@ApiResponse(responseCode=SC_OK, description="the AccountContact object that was created or updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response setContact(@Context Request req,
@@ -518,7 +518,7 @@ public class AccountsResource {
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was updated"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response rootChangePassword(@Context Request req,
@@ -640,7 +640,7 @@ public class AccountsResource {
@ExampleObject(name="mitmproxy is disabled", value="false")
})}),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="if mitmproxy not installed")
@ApiResponse(responseCode=SC_INVALID, description="if mitmproxy not installed")
}
)
public Response mitmStatus(@Context ContainerRequest ctx,
@@ -663,7 +663,7 @@ public class AccountsResource {
@ExampleObject(name="mitmproxy is disabled", value="false")
})}),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="if mitmproxy is not installed or an error occurred enabling it")
@ApiResponse(responseCode=SC_INVALID, description="if mitmproxy is not installed or an error occurred enabling it")
}
)
public Response mitmOn(@Context ContainerRequest ctx,
@@ -686,7 +686,7 @@ public class AccountsResource {
@ExampleObject(name="mitmproxy is disabled", value="false")
})}),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="if mitmproxy is not installed or an error occurred disabling it")
@ApiResponse(responseCode=SC_INVALID, description="if mitmproxy is not installed or an error occurred disabling it")
}
)
public Response mitmOff(@Context ContainerRequest ctx,


+ 17
- 16
bubble-server/src/main/java/bubble/resources/account/AuthResource.java View File

@@ -40,6 +40,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.Cleanup;
@@ -147,7 +148,7 @@ public class AuthResource {
description="Determine if the API is running and ready for login",
responses={
@ApiResponse(responseCode=SC_OK, description="empty response with status 200 if API is ready"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="error with status 422 if API is NOT ready")
@ApiResponse(responseCode=SC_INVALID, description="error with status 422 if API is NOT ready")
}
)
public Response getNodeIsReady(@Context ContainerRequest ctx) {
@@ -200,7 +201,7 @@ public class AuthResource {
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object for the initial admin account, with a new session token"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and activation has already been completed"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred: activation has already been completed, or there were errors processing the ActivationRequest object")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred: activation has already been completed, or there were errors processing the ActivationRequest object")
}
)
public Response activate(@Context Request req,
@@ -266,7 +267,7 @@ public class AuthResource {
parameters={@Parameter(name="restoreKey", description="the restore key")},
responses={
@ApiResponse(responseCode=SC_OK, description="the NotificationReceipt from a successful request to retrieve the backup"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response restore(@NonNull @Context final Request req,
@@ -299,7 +300,7 @@ public class AuthResource {
parameters={@Parameter(name="restoreKey", description="the restore key")},
responses={
@ApiResponse(responseCode=SC_OK, description="upon success a 200 HTTP status with an empty response is returned"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
@NonNull public Response restoreFromPackage(@NonNull @Context final Request req,
@@ -326,8 +327,8 @@ public class AuthResource {
summary="Register a new Account, starts a new API session.",
description="Register a new Account, starts a new API session.",
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was registered, `token` property holds session token"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_OK, description="the Account object that was registered, `token` property holds session token", content=@Content(mediaType=APPLICATION_JSON, schema=@Schema(ref="#/components/schema/Account"))),
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response register(@Context Request req,
@@ -444,7 +445,7 @@ public class AuthResource {
parameters={@Parameter(name="k", description="for a new Bubble that was launched with the lock enabled, the unlock key is required for the first login")},
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response login(@Context Request req,
@@ -525,7 +526,7 @@ public class AuthResource {
parameters={@Parameter(name="session", description="the session token to use for logging in")},
responses={
@ApiResponse(responseCode=SC_OK, description="the Account object that was logged in"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response appLogin(@Context Request req,
@@ -656,7 +657,7 @@ public class AuthResource {
responses={
@ApiResponse(responseCode=SC_OK, description="the NodeKey that was created"),
@ApiResponse(responseCode=SC_FORBIDDEN, description="forbidden if caller is not admin and is accessing any account Account other than themselves"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="validation errors occurred")
@ApiResponse(responseCode=SC_INVALID, description="validation errors occurred")
}
)
public Response rekeyNode(@Context Request req,
@@ -701,7 +702,7 @@ public class AuthResource {
description="Send a reset password message",
responses={
@ApiResponse(responseCode=SC_OK, description="an empty response with HTTP status 200 indicates success"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="if no email address was supplied in the request body")
@ApiResponse(responseCode=SC_INVALID, description="if no email address was supplied in the request body")
}
)
public Response forgotPassword(@Context Request req,
@@ -737,7 +738,7 @@ public class AuthResource {
@ExampleObject(name="if no login requested, returns an empty response", value=""),
@ExampleObject(name="if login requested, returns an Account object with either a valid session token ('token' property) or additional auth factors required (check 'multifactorAuth' property)")
})}),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid")
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
public Response approve(@Context Request req,
@@ -786,7 +787,7 @@ public class AuthResource {
@ExampleObject(name="if no login requested, returns an empty response", value=""),
@ExampleObject(name="if login requested, returns an Account object with either a valid session token ('token' property) or additional auth factors required (check 'multifactorAuth' property)")
})}),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid")
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
public Response authenticator(@Context Request req,
@@ -850,7 +851,7 @@ public class AuthResource {
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="returns an empty JSON object", value="{}")
})}),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid")
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
public Response flushAuthenticatorTokens(@Context Request req,
@@ -870,7 +871,7 @@ public class AuthResource {
content={@Content(mediaType=APPLICATION_JSON, examples={
@ExampleObject(name="returns the denial AccountMessage")
})}),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="a validation error occurred, for example the token might be invalid")
@ApiResponse(responseCode=SC_INVALID, description="a validation error occurred, for example the token might be invalid")
}
)
public Response deny(@Context Request req,
@@ -957,7 +958,7 @@ public class AuthResource {
parameters={@Parameter(name="all", description="logout of all sessions everywhere")},
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="If there is no current session to log out of")
@ApiResponse(responseCode=SC_INVALID, description="If there is no current session to log out of")
}
)
public Response logout(@Context ContainerRequest ctx,
@@ -980,7 +981,7 @@ public class AuthResource {
parameters={@Parameter(name="id", description="UUID or email of user to logout")},
responses={
@ApiResponse(responseCode=SC_OK, description="HTTP status 200 indicates success"),
@ApiResponse(responseCode=SC_PRECONDITION_FAILED, description="If there is no current session to log out of")
@ApiResponse(responseCode=SC_INVALID, description="If there is no current session to log out of")
}
)
public Response logoutUserEverywhere(@Context ContainerRequest ctx,


+ 46
- 4
bubble-server/src/main/java/bubble/resources/account/MeResource.java View File

@@ -35,6 +35,9 @@ import bubble.service.cloud.NodeLaunchMonitor;
import bubble.service.upgrade.BubbleJarUpgradeService;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.Cleanup;
import lombok.Getter;
@@ -75,9 +78,12 @@ import static bubble.resources.account.AuthResource.forgotPasswordMessage;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;
import static org.cobbzilla.util.http.HttpContentTypes.*;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_OK;
import static org.cobbzilla.util.http.HttpStatusCodes.SC_INVALID;
import static org.cobbzilla.util.json.JsonUtil.json;
import static org.cobbzilla.wizard.resources.ResourceUtil.*;
import static org.cobbzilla.wizard.server.RestServerBase.reportError;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.API_TAG_UTILITY;
import static org.cobbzilla.wizard.server.config.OpenApiConfiguration.SEC_API_KEY;

@Consumes(APPLICATION_JSON)
@@ -95,7 +101,14 @@ public class MeResource {
@Autowired private AccountMessageDAO messageDAO;

@GET
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
summary="Get account record for current session",
description="Get account record for current session",
responses={
@ApiResponse(responseCode=SC_OK, description="Account object")
}
)
public Response me(@Context ContainerRequest ctx) {
try {
final Account account = userPrincipal(ctx);
@@ -113,14 +126,28 @@ public class MeResource {
}

@GET @Path(EP_LOCALE)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
summary="Get the account locale",
description="Get the account locale",
responses={
@ApiResponse(responseCode=SC_OK, description="Locale string", content=@Content(mediaType=APPLICATION_JSON, examples={@ExampleObject(name="default locale", value="en_US")}))
}
)
public Response getLocale(@Context ContainerRequest ctx) {
final Account account = userPrincipal(ctx);
return ok(account.getLocale());
}

@POST @Path(EP_LOCALE+"/{locale}")
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
summary="Set the account locale",
description="Set the account locale",
responses={
@ApiResponse(responseCode=SC_OK, description="updated Account object")
}
)
public Response setLocale(@Context ContainerRequest ctx,
@PathParam("locale") String locale) {
final Account account = userPrincipal(ctx);
@@ -150,10 +177,25 @@ public class MeResource {
}

@GET @Path(EP_ERROR_API)
@Operation(tags={API_TAG_UTILITY},
summary="Get error API information",
description="Get error API information",
responses={
@ApiResponse(responseCode=SC_OK, description="a Map of API information")
}
)
public Response errorApi(@Context Request req) { return ok(getErrorApi()); }

@POST @Path(EP_CHANGE_PASSWORD)
@Operation(security=@SecurityRequirement(name=SEC_API_KEY))
@Operation(security=@SecurityRequirement(name=SEC_API_KEY),
tags={API_TAG_ACCOUNT},
summary="Request account password change",
description="Request account password change. A message will be sent to the user with a token to approve the change and set a new password. If the password can be changed directly, this returns the updated Account object. If approvals are required for a password change, an Account object will be returned and the `multifactorAuth` property will indicate what auth methods are required to approve the change.",
responses={
@ApiResponse(responseCode=SC_OK, description="an Account object"),
@ApiResponse(responseCode=SC_INVALID, description="current password was incorrect, or a TOTP token is required")
}
)
public Response changePassword(@Context Request req,
@Context ContainerRequest ctx,
ChangePasswordRequest request) {


+ 1
- 1
utils/cobbzilla-utils

@@ -1 +1 @@
Subproject commit 4c1d7e827aeff02a9dd3dbf76de6127ea9c09c60
Subproject commit 51119dc923d483f8b97fb0de3b36e3ff893e2ee9

+ 1
- 1
utils/cobbzilla-wizard

@@ -1 +1 @@
Subproject commit d5c78b814875ca5298a664314591ecb644a23741
Subproject commit 126e4b4da345a14006998703147f4744c535a0df

Loading…
Cancel
Save