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

components$securitySchemes #57

Merged
merged 29 commits into from
Oct 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d0e6c3b
Implement security_schemes.
jonthegeek Sep 15, 2023
9cbc2df
Add work on oauth2 schemes.
jonthegeek Sep 16, 2023
eb7e30d
Use collate.
jonthegeek Sep 18, 2023
6b89fd0
Rename `in` param to "location".
jonthegeek Sep 21, 2023
cae3888
Clean test names.
jonthegeek Sep 21, 2023
c0edec9
Document ouath classes.
jonthegeek Sep 21, 2023
71fe4d4
Lengths and as's.
jonthegeek Sep 21, 2023
74fb552
Refactor.
jonthegeek Sep 22, 2023
12c296f
Massive security_scheme reorg.
jonthegeek Sep 25, 2023
5f52944
Standardize to "description".
jonthegeek Sep 25, 2023
808e2de
Ouath2 tests.
jonthegeek Sep 25, 2023
093ab2e
Add as_security_scheme_collection()
jonthegeek Sep 25, 2023
8af4d26
Finish security_scheme_collection().
jonthegeek Sep 26, 2023
cf158f9
Finish security_scheme_details().
jonthegeek Sep 26, 2023
5c05c81
Finish as_security_scheme().
jonthegeek Sep 26, 2023
73ae1d2
Remove extra noise from tests.
jonthegeek Sep 28, 2023
c7f0d41
Use as_*() in constructors.
jonthegeek Oct 2, 2023
71516a5
Implement oauth2_security_scheme and friends.
jonthegeek Oct 2, 2023
6bd1123
Abstract my general as_*() functions
jonthegeek Oct 3, 2023
426ef22
More work finishing auth components.
jonthegeek Oct 3, 2023
da3f460
Finish tests for flows.
jonthegeek Oct 3, 2023
8a1b3b6
Finish security scheme tests.
jonthegeek Oct 3, 2023
89f6d14
Add components.
jonthegeek Oct 3, 2023
6225593
Note use of snakecase in as_* documentation.
jonthegeek Oct 4, 2023
bdda967
Log TODOs as issues on GH.
jonthegeek Oct 4, 2023
7b4cc91
Add components to rapid().
jonthegeek Oct 4, 2023
084ee03
Document components.
jonthegeek Oct 4, 2023
0f1769f
Document as_oauth2_security_scheme
jonthegeek Oct 4, 2023
0c22bb2
Repair as_oauth2_security_scheme() test snapshot.
jonthegeek Oct 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
^docs$
^pkgdown$
^principles\.md$
^exploration$
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
.DS_Store
.quarto
docs
exploration
35 changes: 31 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Package: rapid
Title: R 'API' Definitions
Title: R 'API' Descriptions
Version: 0.0.0.9000
Authors@R: c(
person("Jon", "Harmon", , "[email protected]", role = c("aut", "cre"),
comment = c(ORCID = "0000-0003-4781-4346")),
person("The Linux Foundation", role = "cph",
comment = "OpenAPI Specification")
)
Description: Convert an 'API' document ('APID'), such as one that follows
the 'OpenAPI Specification', to an R 'API' definition object (a
Description: Convert an 'API' description ('APID'), such as one that follows
the 'OpenAPI Specification', to an R 'API' description object (a
"rapid"). The rapid object follows the 'OpenAPI Specification' to
make it easy to convert to and from 'API' documents.
License: MIT + file LICENSE
Expand All @@ -20,7 +20,7 @@ Imports:
glue,
purrr,
rlang (>= 1.1.0),
S7 (>= 0.1.0.9000),
S7 (>= 0.1.1),
snakecase,
stbl,
yaml
Expand All @@ -34,3 +34,30 @@ Config/testthat/parallel: true
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
Collate:
'as.R'
'components-security_scheme.R'
'properties.R'
'components-security_scheme-api_key.R'
'components-security_scheme-oauth2-scopes.R'
'components-security_scheme-oauth2-flow.R'
'components-security_scheme-oauth2-authorization_code_flow.R'
'components-security_scheme-oauth2-implicit_flow.R'
'components-security_scheme-oauth2-token_flow.R'
'components-security_scheme-oauth2.R'
'components-security_scheme_details.R'
'components-security_scheme_collection.R'
'components.R'
'info-contact.R'
'info-license.R'
'info.R'
'rapid-package.R'
'servers-server_variables.R'
'servers-string_replacements.R'
'servers.R'
'utils.R'
'validate_in.R'
'validate_lengths.R'
'validate_parallel.R'
'zz-rapid.R'
'zzz.R'
19 changes: 19 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
# Generated by roxygen2: do not edit by hand

export(api_key_security_scheme)
export(as_api_key_security_scheme)
export(as_component_collection)
export(as_contact)
export(as_info)
export(as_license)
export(as_oauth2_authorization_code_flow)
export(as_oauth2_implicit_flow)
export(as_oauth2_security_scheme)
export(as_oauth2_token_flow)
export(as_rapid)
export(as_scopes)
export(as_security_scheme)
export(as_security_scheme_collection)
export(as_security_scheme_details)
export(as_server_variables)
export(as_servers)
export(as_string_replacements)
export(component_collection)
export(contact)
export(info)
export(license)
export(oauth2_authorization_code_flow)
export(oauth2_implicit_flow)
export(oauth2_security_scheme)
export(oauth2_token_flow)
export(rapid)
export(scopes)
export(security_scheme_collection)
export(security_scheme_details)
export(server_variables)
export(servers)
export(string_replacements)
Expand Down
19 changes: 17 additions & 2 deletions R/as.R
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
.as_class <- function(x, target_S7_class, ..., arg = rlang::caller_arg(x), call = rlang::caller_env()) {
force(arg)
x <- .validate_for_as_class(x, target_S7_class, ..., x_arg = arg, call = call)
rlang::inject({
target_S7_class(!!!x)
})
}

.validate_for_as_class <- function(x,
target_S7_class,
extra_names = NULL,
x_arg = rlang::caller_arg(x),
call = rlang::caller_env()) {
if (!length(x)) {
return(NULL)
}

valid_names <- S7::prop_names(target_S7_class())
valid_names <- c(S7::prop_names(target_S7_class()), names(extra_names))

if (rlang::is_named2(x)) {
force(x_arg)
x <- rlang::set_names(x, snakecase::to_snake_case)
if (any(names(x) %in% valid_names)) {
return(as.list(x)[names(x) %in% valid_names])
x <- as.list(x)[names(x) %in% valid_names]
if (length(extra_names)) {
to_rename <- names(x) %in% names(extra_names)
names(x)[to_rename] <- extra_names[names(x)[to_rename]]
}
return(x)
}
}

Expand All @@ -21,6 +35,7 @@
"{.arg {x_arg}} must have names {.or {.val {valid_names}}}.",
"*" = "Any other names are ignored."
),
class = "rapid_missing_names",
call = call
)
}
98 changes: 98 additions & 0 deletions R/components-security_scheme-api_key.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#' @include properties.R
#' @include components-security_scheme.R
NULL

#' API key security schemes
#'
#' Defines an API key security scheme that can be used by the operations.
#'
#' @param parameter_name Character vector (required). The names of the header,
#' query or cookie parameters to be used.
#' @param location Character vector (required). The location of the API key.
#' Valid values are "query", "header" or "cookie".
#'
#' @return An `api_key_security_scheme` S7 object, with fields `parameter_name`
#' and `location`.
#' @export
#'
#' @examples
#' api_key_security_scheme(
#' parameter_name = "Authorization",
#' location = "header"
#' )
api_key_security_scheme <- S7::new_class(
name = "api_key_security_scheme",
package = "rapid",
parent = security_scheme,
properties = list(
parameter_name = character_scalar_property("parameter_name"),
location = character_scalar_property("location")
),
constructor = function(parameter_name = character(),
location = character()) {
S7::new_object(
S7::S7_object(),
parameter_name = parameter_name,
location = location
)
},
validator = function(self) {
validate_parallel(
self,
"parameter_name",
required = "location"
) %|0|% validate_in_fixed(
self,
"location",
c("query", "header", "cookie")
)
}
)

S7::method(length, api_key_security_scheme) <- function(x) {
length(x@parameter_name)
}

#' Coerce lists and character vectors to API key security schemes
#'
#' `as_api_key_security_scheme()` turns an existing object into an
#' `api_key_security_scheme`. This is in contrast with
#' [api_key_security_scheme()], which builds an `api_key_security_scheme` from
#' individual properties.
#'
#' @inheritParams rlang::args_dots_empty
#' @inheritParams rlang::args_error_context
#' @param x The object to coerce. Must be empty or be a list or character vector
#' with names "name" and either "in" or "location", or names that can be
#' coerced to those names via [snakecase::to_snake_case()]. Additional names
#' are ignored.
#'
#' @return An `api_key_security_scheme` as returned by
#' [api_key_security_scheme()].
#' @export
as_api_key_security_scheme <- S7::new_generic(
"as_api_key_security_scheme",
dispatch_args = "x"
)

S7::method(as_api_key_security_scheme, api_key_security_scheme) <- function(x) {
x
}

S7::method(as_api_key_security_scheme, class_list | class_character) <- function(x) {
.as_class(
x,
api_key_security_scheme,
extra_names = c("in" = "location", "name" = "parameter_name")
)
}

S7::method(as_api_key_security_scheme, class_missing | NULL | S7::new_S3_class("S7_missing")) <- function(x) {
api_key_security_scheme()
}

S7::method(as_api_key_security_scheme, class_any) <- function(x, ..., arg = rlang::caller_arg(x)) {
cli::cli_abort(
"Can't coerce {.arg {arg}} {.cls {class(x)}} to {.cls api_key_security_scheme}."
)
}
101 changes: 101 additions & 0 deletions R/components-security_scheme-oauth2-authorization_code_flow.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#' @include components-security_scheme-oauth2-flow.R
NULL

#' OAuth2 authorization code flow object
#'
#' An `oauth2_authorization_code_flow` object describes the configuration for
#' the OAuth Authorization Code flow. Previously called `accessCode` in OpenAPI
#' 2.0.
#'
#' @inheritParams oauth2_flow
#' @inheritParams rlang::args_dots_empty
#' @inheritParams oauth2_implicit_flow
#' @inheritParams oauth2_token_flow
#'
#' @export
#' @examples
#' oauth2_authorization_code_flow(
#' authorization_url = "https://example.com/authorize",
#' token_url = "https://example.com/token",
#' refresh_url = "https://example.com/refresh",
#' scopes = scopes(
#' name = c("server:read", "server:write"),
#' description = c("Read server settings", "Write server settings")
#' )
#' )
oauth2_authorization_code_flow <- S7::new_class(
name = "oauth2_authorization_code_flow",
package = "rapid",
parent = oauth2_flow,
properties = list(
authorization_url = character_scalar_property("authorization_url"),
token_url = character_scalar_property("token_url")
),
constructor = function(authorization_url = character(),
token_url = character(),
...,
refresh_url = character(),
scopes = character()) {
check_dots_empty()
S7::new_object(
S7::S7_object(),
authorization_url = authorization_url,
token_url = token_url,
refresh_url = refresh_url,
scopes = as_scopes(scopes)
)
},
validator = function(self) {
validate_lengths(
self,
"authorization_url",
required_same = "token_url",
optional_same = "refresh_url",
optional_any = "scopes"
)
}
)

S7::method(length, oauth2_authorization_code_flow) <- function(x) {
length(x@authorization_url)
}

#' Coerce lists and character vectors to OAuth2 authorization code flows
#'
#' `as_oauth2_authorization_code_flow()` turns an existing object into an
#' `oauth2_authorization_code_flow`. This is in contrast with
#' [oauth2_authorization_code_flow()], which builds an
#' `oauth2_authorization_code_flow` from individual properties.
#'
#' @inheritParams rlang::args_dots_empty
#' @inheritParams rlang::args_error_context
#' @param x The object to coerce. Must be empty or be a list of named lists,
#' each with names "refresh_url", "scopes", "authorization_url", and/or
#' "token_url", or names that can be coerced to those names via
#' [snakecase::to_snake_case()]. Additional names are ignored.
#'
#' @return An `oauth2_authorization_code_flow` as returned by
#' [oauth2_authorization_code_flow()].
#' @export
as_oauth2_authorization_code_flow <- S7::new_generic(
"as_oauth2_authorization_code_flow",
dispatch_args = "x"
)

S7::method(as_oauth2_authorization_code_flow, oauth2_authorization_code_flow) <- function(x) {
x
}

S7::method(as_oauth2_authorization_code_flow, class_list | class_character) <- function(x) {
.as_class(x, oauth2_authorization_code_flow)
}

S7::method(as_oauth2_authorization_code_flow, class_missing | NULL | S7::new_S3_class("S7_missing")) <- function(x) {
oauth2_authorization_code_flow()
}

S7::method(as_oauth2_authorization_code_flow, class_any) <- function(x, ..., arg = rlang::caller_arg(x)) {
cli::cli_abort(
"Can't coerce {.arg {arg}} {.cls {class(x)}} to {.cls oauth2_authorization_code_flow}."
)
}
27 changes: 27 additions & 0 deletions R/components-security_scheme-oauth2-flow.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#' @include components-security_scheme-oauth2-scopes.R
#' @include properties.R
NULL

#' OAuth2 flow object
#'
#' This is an abstract class that is used to define specific types of OAuth2
#' flow objects.
#'
#' @param refresh_url Character scalar (optional). The URL to be used for
#' obtaining refresh tokens. This must be in the form of a URL. The OAuth2
#' standard requires the use of TLS.
#' @param scopes An optional [scopes()] object with the available scopes for the
#' OAuth2 security scheme.
#'
#' @keywords internal
#' @seealso [oauth2_token_flow()], [oauth2_implicit_flow()], and
#' [oauth2_authorization_code_flow()]
oauth2_flow <- S7::new_class(
name = "oauth2_flow",
package = "rapid",
properties = list(
refresh_url = character_scalar_property("refresh_url"),
scopes = scopes
),
abstract = TRUE
)
Loading