Swagger docs for OAuth2Controller and OAuth2ConfigTemplateController

This commit is contained in:
Viacheslav Klimov 2021-10-17 21:39:04 +03:00 committed by Andrew Shvayka
parent d7c09b9f67
commit 1f94ff9732
12 changed files with 142 additions and 9 deletions

View File

@ -15,12 +15,18 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.audit.ActionType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.OAuth2ClientRegistrationTemplateId;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate;
@ -37,6 +43,10 @@ import java.util.List;
public class OAuth2ConfigTemplateController extends BaseController {
private static final String CLIENT_REGISTRATION_TEMPLATE_ID = "clientRegistrationTemplateId";
private static final String OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION = "Client registration template is OAuth2 provider configuration template with default settings for registering new OAuth2 clients";
@ApiOperation(value = "Create or update OAuth2 client registration template (saveClientRegistrationTemplate)",
notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
@ -49,10 +59,13 @@ public class OAuth2ConfigTemplateController extends BaseController {
}
}
@ApiOperation(value = "Delete OAuth2 client registration template by id (deleteClientRegistrationTemplate)",
notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/{clientRegistrationTemplateId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteClientRegistrationTemplate(@PathVariable(CLIENT_REGISTRATION_TEMPLATE_ID) String strClientRegistrationTemplateId) throws ThingsboardException {
public void deleteClientRegistrationTemplate(@ApiParam(value = "String representation of client registration template id to delete", example = "139b1f81-2f5d-11ec-9dbe-9b627e1a88f4")
@PathVariable(CLIENT_REGISTRATION_TEMPLATE_ID) String strClientRegistrationTemplateId) throws ThingsboardException {
checkParameter(CLIENT_REGISTRATION_TEMPLATE_ID, strClientRegistrationTemplateId);
try {
accessControlService.checkPermission(getCurrentUser(), Resource.OAUTH2_CONFIGURATION_TEMPLATE, Operation.DELETE);
@ -63,6 +76,8 @@ public class OAuth2ConfigTemplateController extends BaseController {
}
}
@ApiOperation(value = "Get the list of all OAuth2 client registration templates (getClientRegistrationTemplates)",
notes = OAUTH2_CLIENT_REGISTRATION_TEMPLATE_DEFINITION)
@PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
@ResponseBody
@ -74,4 +89,5 @@ public class OAuth2ConfigTemplateController extends BaseController {
throw handleException(e);
}
}
}

View File

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
@ -50,10 +52,20 @@ public class OAuth2Controller extends BaseController {
@Autowired
private OAuth2Configuration oAuth2Configuration;
@ApiOperation(value = "Get OAuth2 clients (getOAuth2Clients)", notes = "Get the list of OAuth2 clients " +
"to log in with, available for such domain scheme (HTTP or HTTPS) (if x-forwarded-proto request header is present - " +
"the scheme is known from it) and domain name and port (port may be known from x-forwarded-port header)")
@RequestMapping(value = "/noauth/oauth2Clients", method = RequestMethod.POST)
@ResponseBody
public List<OAuth2ClientInfo> getOAuth2Clients(HttpServletRequest request,
@ApiParam(value = "Mobile application package name, to find OAuth2 clients " +
"where there is configured mobile application with such package name")
@RequestParam(required = false) String pkgName,
@ApiParam(value = "Platform type to search OAuth2 clients for which " +
"the usage with this platform type is allowed in the settings. " +
"If platform type is not one of allowable values - it will just be ignored",
allowableValues = "WEB, ANDROID, IOS")
@RequestParam(required = false) String platform) throws ThingsboardException {
try {
if (log.isDebugEnabled()) {
@ -76,6 +88,7 @@ public class OAuth2Controller extends BaseController {
}
}
@ApiOperation(value = "Get current OAuth2 settings (getCurrentOAuth2Info)")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/oauth2/config", method = RequestMethod.GET, produces = "application/json")
@ResponseBody
@ -88,6 +101,7 @@ public class OAuth2Controller extends BaseController {
}
}
@ApiOperation(value = "Save OAuth2 settings (saveOAuth2Info)")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/oauth2/config", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
@ -101,6 +115,10 @@ public class OAuth2Controller extends BaseController {
}
}
@ApiOperation(value = "Get OAuth2 log in processing URL (getLoginProcessingUrl)", notes = "Returns the URL enclosed in " +
"double quotes. After successful authentication with OAuth2 provider, it makes a redirect to this path so that the platform can do " +
"further log in processing. This URL may be configured as 'security.oauth2.loginProcessingUrl' property in yml configuration file, or " +
"as 'SECURITY_OAUTH2_LOGIN_PROCESSING_URL' env variable. By default it is '/login/oauth2/code/'")
@PreAuthorize("hasAnyAuthority('SYS_ADMIN')")
@RequestMapping(value = "/oauth2/loginProcessingUrl", method = RequestMethod.GET)
@ResponseBody
@ -112,4 +130,5 @@ public class OAuth2Controller extends BaseController {
throw handleException(e);
}
}
}

View File

@ -15,19 +15,36 @@
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@Builder(toBuilder = true)
@EqualsAndHashCode
@Data
@ToString
@ApiModel
public class OAuth2BasicMapperConfig {
@ApiModelProperty(value = "Email attribute key of OAuth2 principal attributes. " +
"Must be specified for BASIC mapper type and cannot be specified for GITHUB type")
private final String emailAttributeKey;
@ApiModelProperty(value = "First name attribute key")
private final String firstNameAttributeKey;
@ApiModelProperty(value = "Last name attribute key")
private final String lastNameAttributeKey;
@ApiModelProperty(value = "Tenant naming strategy. For DOMAIN type, domain for tenant name will be taken from the email (substring before '@')", required = true)
private final TenantNameStrategyType tenantNameStrategy;
@ApiModelProperty(value = "Tenant name pattern for CUSTOM naming strategy. " +
"OAuth2 attributes in the pattern can be used by enclosing attribute key in '%{' and '}'", example = "%{email}")
private final String tenantNamePattern;
@ApiModelProperty(value = "Customer name pattern. When creating a user on the first OAuth2 log in, if specified, " +
"customer name will be used to create or find existing customer in the platform and assign customerId to the user")
private final String customerNamePattern;
@ApiModelProperty(value = "Name of the tenant's dashboard to set as default dashboard for newly created user")
private final String defaultDashboardName;
@ApiModelProperty(value = "Whether default dashboard should be open in full screen")
private final boolean alwaysFullScreen;
}

View File

@ -15,19 +15,26 @@
*/
package org.thingsboard.server.common.data.oauth2;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
@EqualsAndHashCode
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel
public class OAuth2ClientInfo {
@ApiModelProperty(value = "OAuth2 client name", example = "GitHub")
private String name;
@ApiModelProperty(value = "Name of the icon, displayed on OAuth2 log in button", example = "github-logo")
private String icon;
@ApiModelProperty(value = "URI for OAuth2 log in. On HTTP GET request to this URI, it redirects to the OAuth2 provider page",
example = "/oauth2/authorization/8352f191-2b4d-11ec-9ed1-cbf57c026ecc")
private String url;
public OAuth2ClientInfo(OAuth2ClientInfo oauth2ClientInfo) {
@ -35,4 +42,5 @@ public class OAuth2ClientInfo {
this.icon = oauth2ClientInfo.getIcon();
this.url = oauth2ClientInfo.getUrl();
}
}

View File

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.common.data.oauth2;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@ -29,20 +31,34 @@ import java.util.List;
@Data
@ToString
@NoArgsConstructor
@ApiModel
public class OAuth2ClientRegistrationTemplate extends SearchTextBasedWithAdditionalInfo<OAuth2ClientRegistrationTemplateId> implements HasName {
@ApiModelProperty(value = "OAuth2 provider identifier (e.g. its name)", required = true)
private String providerId;
@ApiModelProperty(value = "Default config for mapping OAuth2 log in response to platform entities")
private OAuth2MapperConfig mapperConfig;
@ApiModelProperty(value = "Default authorization URI of the OAuth2 provider")
private String authorizationUri;
@ApiModelProperty(value = "Default access token URI of the OAuth2 provider")
private String accessTokenUri;
@ApiModelProperty(value = "Default OAuth scopes that will be requested from OAuth2 platform")
private List<String> scope;
@ApiModelProperty(value = "Default user info URI of the OAuth2 provider")
private String userInfoUri;
@ApiModelProperty(value = "Default name of the username attribute in OAuth2 provider log in response")
private String userNameAttributeName;
@ApiModelProperty(value = "Default JSON Web Key URI of the OAuth2 provider")
private String jwkSetUri;
@ApiModelProperty(value = "Default client authentication method to use: 'BASIC' or 'POST'")
private String clientAuthenticationMethod;
@ApiModelProperty(value = "Comment for OAuth2 provider")
private String comment;
@ApiModelProperty(value = "Default log in button icon for OAuth2 provider")
private String loginButtonIcon;
@ApiModelProperty(value = "Default OAuth2 provider label")
private String loginButtonLabel;
@ApiModelProperty(value = "Help link for OAuth2 provider")
private String helpLink;
public OAuth2ClientRegistrationTemplate(OAuth2ClientRegistrationTemplate clientRegistrationTemplate) {

View File

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.common.data.oauth2;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -28,7 +30,10 @@ import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ApiModel
public class OAuth2DomainInfo {
@ApiModelProperty(value = "Domain scheme. Mixed scheme means than both HTTP and HTTPS are going to be used", required = true)
private SchemeType scheme;
@ApiModelProperty(value = "Domain name. Cannot be empty", required = true)
private String name;
}

View File

@ -15,7 +15,14 @@
*/
package org.thingsboard.server.common.data.oauth2;
import lombok.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.List;
@ -25,7 +32,10 @@ import java.util.List;
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@ApiModel
public class OAuth2Info {
@ApiModelProperty("Whether OAuth2 settings are enabled or not")
private boolean enabled;
@ApiModelProperty(value = "List of configured OAuth2 clients. Cannot contain null values", required = true)
private List<OAuth2ParamsInfo> oauth2ParamsInfos;
}

View File

@ -15,6 +15,7 @@
*/
package org.thingsboard.server.common.data.oauth2;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -25,9 +26,14 @@ import lombok.ToString;
@Data
@ToString
public class OAuth2MapperConfig {
@ApiModelProperty(value = "Whether user should be created if not yet present on the platform after successful authentication")
private boolean allowUserCreation;
@ApiModelProperty(value = "Whether user credentials should be activated when user is created after successful authentication")
private boolean activateUser;
@ApiModelProperty(value = "Type of OAuth2 mapper. Depending on this param, different mapper config fields must be specified", required = true)
private MapperType type;
@ApiModelProperty(value = "Mapper config for BASIC and GITHUB mapper types")
private OAuth2BasicMapperConfig basic;
@ApiModelProperty(value = "Mapper config for CUSTOM mapper type")
private OAuth2CustomMapperConfig custom;
}

View File

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.common.data.oauth2;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -28,7 +30,10 @@ import lombok.ToString;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ApiModel
public class OAuth2MobileInfo {
@ApiModelProperty(value = "Application package name. Cannot be empty", required = true)
private String pkgName;
@ApiModelProperty(value = "Application secret. The length must be at least 16 characters", required = true)
private String appSecret;
}

View File

@ -15,6 +15,8 @@
*/
package org.thingsboard.server.common.data.oauth2;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -30,10 +32,16 @@ import java.util.List;
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@ApiModel
public class OAuth2ParamsInfo {
@ApiModelProperty(value = "List of configured domains where OAuth2 platform will redirect a user after successful " +
"authentication. Cannot be empty. There have to be only one domain with specific name with scheme type 'MIXED'. " +
"Configured domains with the same name must have different scheme types", required = true)
private List<OAuth2DomainInfo> domainInfos;
@ApiModelProperty(value = "Mobile applications settings. Application package name must be unique within the list", required = true)
private List<OAuth2MobileInfo> mobileInfos;
@ApiModelProperty(value = "List of OAuth2 provider settings. Cannot be empty", required = true)
private List<OAuth2RegistrationInfo> clientRegistrations;
}

View File

@ -16,7 +16,14 @@
package org.thingsboard.server.common.data.oauth2;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.util.List;
@ -26,19 +33,34 @@ import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ApiModel
public class OAuth2RegistrationInfo {
@ApiModelProperty(value = "Config for mapping OAuth2 log in response to platform entities", required = true)
private OAuth2MapperConfig mapperConfig;
@ApiModelProperty(value = "OAuth2 client ID. Cannot be empty", required = true)
private String clientId;
@ApiModelProperty(value = "OAuth2 client secret. Cannot be empty", required = true)
private String clientSecret;
@ApiModelProperty(value = "Authorization URI of the OAuth2 provider. Cannot be empty", required = true)
private String authorizationUri;
@ApiModelProperty(value = "Access token URI of the OAuth2 provider. Cannot be empty", required = true)
private String accessTokenUri;
@ApiModelProperty(value = "OAuth scopes that will be requested from OAuth2 platform. Cannot be empty", required = true)
private List<String> scope;
@ApiModelProperty(value = "User info URI of the OAuth2 provider")
private String userInfoUri;
@ApiModelProperty(value = "Name of the username attribute in OAuth2 provider response. Cannot be empty")
private String userNameAttributeName;
@ApiModelProperty(value = "JSON Web Key URI of the OAuth2 provider")
private String jwkSetUri;
@ApiModelProperty(value = "Client authentication method to use: 'BASIC' or 'POST'. Cannot be empty", required = true)
private String clientAuthenticationMethod;
@ApiModelProperty(value = "OAuth2 provider label. Cannot be empty", required = true)
private String loginButtonLabel;
@ApiModelProperty(value = "Log in button icon for OAuth2 provider")
private String loginButtonIcon;
@ApiModelProperty(value = "List of platforms for which usage of the OAuth2 client is allowed (empty for all allowed)")
private List<PlatformType> platforms;
@ApiModelProperty(value = "Additional info of OAuth2 client (e.g. providerName)", required = true)
private JsonNode additionalInfo;
}

View File

@ -16,6 +16,7 @@
package org.thingsboard.server.dao.oauth2;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@ -224,7 +225,7 @@ public class OAuth2ServiceImpl extends AbstractEntityService implements OAuth2Se
if (StringUtils.isEmpty(clientRegistration.getAccessTokenUri())) {
throw new DataValidationException("Token uri should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getScope())) {
if (CollectionUtils.isEmpty(clientRegistration.getScope())) {
throw new DataValidationException("Scope should be specified!");
}
if (StringUtils.isEmpty(clientRegistration.getUserNameAttributeName())) {