{"id":7910,"date":"2021-03-09T01:00:51","date_gmt":"2021-03-09T01:00:51","guid":{"rendered":"https:\/\/staging-site.42crunch.com\/?p=7910"},"modified":"2022-11-24T11:24:01","modified_gmt":"2022-11-24T11:24:01","slug":"springfox-guide-security-definitions","status":"publish","type":"post","link":"https:\/\/staging2022.42crunch.com\/springfox-guide-security-definitions\/","title":{"rendered":"Creating High Quality OAS Definitions with Springfox – Part 1: Security Definitions"},"content":{"rendered":"
Spring Boot is a popular framework to build applications and APIs. Leveraging the Springfox project and code annotations, developers can generate OAS files with a high 42Crunch Security Audit score.<\/span><\/p>\n The <\/span>42Crunch Security Audit<\/span><\/a> is one of 3 services from the <\/span>42Crunch API Security Platform<\/span><\/a>: it consumes OpenAPI (Swagger) files and analyzes them along two axes: security and data.<\/span><\/p>\n Our customers use two approaches:<\/span><\/p>\n In this document, we focus on the core annotations that impact the 42Crunch audit score and therefore allow us to generate a powerful allowlist to protect your APIs.<\/span><\/p>\n This is not a beginners guide to Springfox: if you’ve never used Springfox before, please start by following <\/span>this tutorial.<\/span><\/a><\/p>\n Over 30% of the audit score is based on security definitions and how they are applied. Security definitions define how the API is secured: <\/span>basicauth<\/span><\/i>, <\/span>api key<\/span><\/i> and <\/span>OAuth2<\/span><\/i> are the three authentication types supported by the specification at this time.<\/span><\/p>\n We will explain how to add an API key definition and then an OAuth2 definition, which are the most commonly used ones.<\/span><\/p>\n Our goal is to add the following security definition to our OAS document: in this case, we have an API key which is passed in a header called x-access-token.<\/p>\n We first need to add a securityScheme<\/strong> to the API Docket definition, as follows:<\/p>\n The security scheme operation compiles the list of security definitions that can be used in the API. Let’s start by adding a simple API key definition. <\/span>We first declare the API key scheme:<\/span><\/p>\n We then add this scheme to a list of schemes. The <\/span>securitySchemes<\/span> on the Docket configuration expects a list of security schemes, which you can build as follows:<\/span><\/p>\n The resulting OpenAPI definition looks like this:<\/p>\n If our API is using an access token generated through OAuth, we can describe it using an OAuth scheme object.<\/span><\/p>\n In this function, we declare the OAuth grant type (here AuthorizationCodeGrant) including the authorization and token endpoints. If scopes are associated, they are defined in an array.<\/p>\n Note that the mandatory CLIENT_ID, CLIENT_SECRET, and OAuth token information are used as part of the Swagger UI rendering (they are not used in the OpenAPI file itself).<\/span><\/p>\n The corresponding definition within the OpenAPI definition is as follows:<\/span><\/p>\n Should you want to use both the APIKey and OAuth security definitions, simply add them both to the declaration, like this:<\/span><\/p>\n Once you have defined the security schemes you will have for your service (API), we can now define how to apply them over it. In our example in Part 1, we defined both schemes: API Key and OAuth, and according to the OAS specification, we can inject the schemas according to our needs, we can let the API with a global security schema, or we can have it defined using a security granularity by resource.\u00a0<\/span><\/p>\n In order to define the global authentication scheme, you need to add the respective authorizations<\/strong> annotation at the controller level, as the following example:<\/span><\/p>\n This code snippet sets the global security scheme for this API to be\u00a0 <\/span>access-token<\/span><\/em>.<\/span><\/p>\n You may need to define a security scheme at the resource level, in other words, you can say:\u00a0<\/span><\/p>\n To achieve this, you need to add the authorizations<\/strong> annotation at the API operation level, like this:\u00a0<\/span><\/p>\n Similarly, you can specify OAuth2 as the required security scheme for another operation, for example the DELETE operation.\u00a0<\/span><\/p>\n It is possible to add custom OAS extensions via Springfox to your definitions. This can be used to inject 42Crunch specific extensions, as illustrated below:<\/span><\/p>\n This is the resulting OAS snippet:<\/p>\n This OAS extension allows you to disable authentication checks from the 42Crunch Security Audit on operations in your API that do not need authentication, for example login or register operations used to authenticate.<\/span> The approach presented in this post will let you generate rich, hardened OpenAPI definitions and remediate issues reported by the <\/span>42Crunch Security Audit<\/span><\/a>. Adding annotations also brings the benefit of full synchronization between the code and the API contract, which can then be used to test and protect your APIs using additional 42Crunch platform services.<\/span><\/p>\n Spring Boot is a popular framework to build applications and APIs. Leveraging the Springfox project and code annotations, developers can generate OAS files with a high 42Crunch Security Audit score. What is the 42Crunch Security Audit? The 42Crunch Security Audit is one of 3 services from the 42Crunch API Security Platform: it consumes OpenAPI (Swagger) […]<\/p>\n","protected":false},"author":11,"featured_media":11327,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"none","_seopress_titles_title":"Creating High Quality OAS Definitions with Springfox - Part 1","_seopress_titles_desc":"Leveraging the Springfox project and code annotations, developers can generate OAS (OpenAPI Specification) files with a high API audit score.","_seopress_robots_index":"","site-sidebar-layout":"default","site-content-layout":"default","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"disabled","ast-hfb-above-header-display":"disabled","ast-hfb-below-header-display":"disabled","ast-hfb-mobile-header-display":"disabled","site-post-title":"disabled","ast-breadcrumbs-content":"disabled","ast-featured-img":"disabled","footer-sml-layout":"disabled","theme-transparent-header-meta":"default","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[6,26],"tags":[16,25],"class_list":["post-7910","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","category-popular","tag-api-security-training","tag-api-testing"],"_links":{"self":[{"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/posts\/7910"}],"collection":[{"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/comments?post=7910"}],"version-history":[{"count":0,"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/posts\/7910\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/media\/11327"}],"wp:attachment":[{"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/media?parent=7910"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/categories?post=7910"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/staging2022.42crunch.com\/wp-json\/wp\/v2\/tags?post=7910"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}What is the 42Crunch Security Audit?<\/h2>\n
\n
Producing a High Quality OpenAPI File<\/h2>\n
\n
OAS Security Definitions<\/h2>\n
Using API keys<\/h3>\n
"securityDefinitions": {\n "access-token": {\n "type": "apiKey",\n "in": "header",\n "name": "x-access-token",\n "description": "Most operations need to user token retrieved calling \/api\/login"\n }\n }\n<\/code><\/pre>\n
@Bean\npublic Docket apiDocket() {\n return new Docket(DocumentationType.SWAGGER_2)\n\t .select()\n\t .apis(RequestHandlerSelectors.basePackage("com.xliic"))\t\n\t .paths(PathSelectors.any())\n\t .build()\n\t .apiInfo(getApiInfo())\n\t .produces(DEFAULT_PRODUCES_AND_CONSUMES)\n\t .consumes(DEFAULT_PRODUCES_AND_CONSUMES)\n\t .useDefaultResponseMessages(false)\n\t .securitySchemes(securitySchemes()))\n\t .enableUrlTemplating(false)\n\t .host("apis.xliic.com")\n\t .protocols(Stream.of("https").collect(toSet()));\n}\n<\/code><\/pre>\n
\nprivate ApiKey apikeyScheme() {\n\t return new ApiKey("access-token", "x-access-token", "header");\n\t}\n<\/code><\/pre>\n
\nprivate ArrayList securitySchemes () {\n ArrayList secList = Lists.newArrayList();\n <strong>secList.add(apikeyScheme());<\/strong>\t\t\n return secList;\n}\n<\/code><\/pre>\n
"securityDefinitions": {\n "access-token": {\n "type": "apiKey",\n "name": "x-access-token",\n "in": "header"\n }\n },<\/code><\/pre>\n
Using OAuth as authentication scheme<\/h3>\n
private OAuth oauthScheme() {\n GrantType grantType = \n\t new AuthorizationCodeGrant( \n\t \tnew TokenRequestEndpoint(Constants.OAUTH_SERVER + "\/authorize", "CLIENT_ID", "CLIENT_SECRET"), \n\t \tnew TokenEndpoint(Constants.OAUTH_SERVER + "\/token", "oauthtoken"));\n\t OAuth oauth = new OAuth ("oauth", Arrays.asList(scopes()), Arrays.asList(grantType));\n return oauth;\n} <\/code><\/pre>\n
private AuthorizationScope[] scopes() {\n\t AuthorizationScope[] scopes = { \n\t new AuthorizationScope("read", "for read operations"), \n\t new AuthorizationScope("write", "for write operations"), \n\t new AuthorizationScope("delete", "for delete operations") };\n\t return scopes;\n\t}\n<\/code><\/pre>\n
\n"securityDefinitions": {\n "oauth": {\n "type": "oauth2",\n "authorizationUrl": "https:\/\/oauth.acme.com\/authorize",\n "tokenUrl": "https:\/\/oauth.acme.com\/token",\n "flow": "accessCode",\n "scopes": {\n "read": "for read operations",\n "write": "for write operations",\n "delete": "for delete operations"\n }\n }\n }<\/code><\/pre>\n
private ArrayList securitySchemes () {\n \/\/ Add the two security definitions to a single list\n ArrayList secList = Lists.newArrayList();\n secList.add(apikeyScheme());\n secList.add(oauthScheme());\n\t\t\n return secList;\n}\n<\/code><\/pre>\n
Applying Security<\/b><\/h2>\n
Applying security at API level<\/b><\/h3>\n
\n@RestController\n@RequestMapping("\/v2")\n@Api(value = "Set of endpoints for Creating, Retrieving, Updating and Deleting of Persons.", authorizations = {\n@Authorization(value = "access-token") })\npublic class PersonController {\n<\/code><\/pre>\n
Applying security at operation level<\/b><\/h3>\n
\n
\n
\n
\n@RequestMapping(method = RequestMethod.GET, path = "\/person\/{id}", produces = MediaType.APPLICATION_JSON_VALUE)\n@ApiOperation(nickname = "getPersonByID", value = "Retrieve Person by id", notes = "Returns a specific person by their identifier. 404 if does not exist.", response = Person.class,\n authorizations = {\n @Authorization(value = "access-token") })\n<\/code><\/pre>\n
\n@RequestMapping(method = RequestMethod.DELETE, path = "\/person\/{id}")\n@ApiOperation(value = "Delete Person by id", notes = "Deletes a person from the system. 404 if the person's identifier is not found.", \n authorizations = {\n @Authorization(value="oauth",scopes = {@AuthorizationScope(scope="delete",description = "Delete person")})})<\/code><\/pre>\n
42Crunch Extensions Support<\/h2>\n
\n@RequestMapping(method = RequestMethod.POST, path = "\/login", produces = MediaType.APPLICATION_JSON_VALUE)\n@ApiOperation(value = "Create a person", notes = "API login ", extensions = {\n@Extension(properties = { @ExtensionProperty(name = "x-42c-no-authentication", value = "true") })\n})\n\npublic Person login(\n@RequestParam @Min(10) @Max(50) @Pattern(regexp = Constants.EMAIL_REGEX) String email,\n@RequestParam @Min(10) @Max(50) @Pattern(regexp = Constants.PASSWORD_REGEX) String password)\n<\/code><\/pre>\n
\n"paths":{\n "\/login":{\n "post":{\n ...\n "deprecated":false,\n "x-42c-no-authentication":"true"\n}\n<\/code><\/pre>\n
\n<\/b><\/p>\nConclusion\u00a0<\/b><\/h2>\n
References:<\/span><\/h3>\n
https:\/\/medium.com\/future-vision\/the-great-authenticators-of-rest-738e81109331<\/span><\/a><\/pre>\n","protected":false},"excerpt":{"rendered":"