Skip to content

Commit

Permalink
Merge pull request #10703 from fcfang123/issue-10663
Browse files Browse the repository at this point in the history
feat:oauth2 增加密码模式 #10663
  • Loading branch information
bkci-bot authored Sep 26, 2024
2 parents e94031e + 970b815 commit e1b68e6
Show file tree
Hide file tree
Showing 33 changed files with 314 additions and 152 deletions.
10 changes: 3 additions & 7 deletions scripts/bkenv.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# ci.env template, generated at 2021-09-09 16:40:32

##########
# 0-依赖声明
##########
Expand Down Expand Up @@ -75,7 +74,8 @@ BK_CI_MONITOR_REGISTER=false
BK_CI_MONITOR_URL=
# BK_CI_MONITOR_URL 监控对接权限中心SYSTEM_ID,无默认值. 无需修改. 声明依赖, 蓝鲸环境下会自动填充. 其他环境无需填写.
BK_CI_MONITOR_IAM_SYSTEM=

# BK_CI_AUTH_AES_AUTH_KEY 加密Key值,初始值为I4U1SzSNRaDYufbE,若用到oauth2密码模式,最好对该值进行修改。
BK_CI_AUTH_AES_AUTH_KEY=I4U1SzSNRaDYufbE
##########
# 1-基础配置
##########
Expand Down Expand Up @@ -149,7 +149,6 @@ BK_ESB_HOST=
BK_CI_PUBLIC_PATH=""
# BK_CI_FRONTEND_INDEX
BK_CI_FRONTEND_INDEX="rewrite .* /\$subsystem/index.html break"

##########
# 2-公共依赖
##########
Expand Down Expand Up @@ -231,7 +230,6 @@ BK_CI_KUBERNETES_WEBCONSOLE_PROXY=
BK_CI_SM4_KEY=s31^dDjd!3k
# BK_CI_SM4_ENABLED
BK_CI_SM4_ENABLED=false

##########
# 3-微服务配置
##########
Expand Down Expand Up @@ -310,7 +308,7 @@ BK_CI_PROJECT_ROUTER_TAG=$BK_CI_CONSUL_DISCOVERY_TAG
# BK_CI_STREAM_URL stream独立页面地址
BK_CI_STREAM_URL=
# BK_CI_GIT_GITHUB_URL stream当前对接的Git源的类型如 CODE_GIT GITHUB 等,参考代码中的ScmType
BK_CI_STREAM_SCM_TYPE= CODE_GIT
BK_CI_STREAM_SCM_TYPE=CODE_GIT
# BK_CI_GIT_GITCODE_URL stream跳转时用到的git url地址
BK_CI_STREAM_GIT_URL=
# BK_CI_STREAM_REPORT_PREFIX stream展示报告时的前置链接
Expand Down Expand Up @@ -363,7 +361,6 @@ BK_CI_OPENAPI_VERIFY_PROJECT=false
BK_CI_AUDIT_ENABLED=false
# 是否开启构建记录清理
BK_CI_BUILD_DATA_CLEAR_SWITCH=false

##########
# 4-微服务依赖
##########
Expand Down Expand Up @@ -473,7 +470,6 @@ BK_CI_API_TOKEN_EXPIRED_MILLISECOND=86400000
BK_CI_DISPATCH_KUBERNETES_NS=default
# BK_CI_DISPATCH_THIRD_AGENT_WORKER_ERROR_TEMPLATE dispatch服务发送worker启动失败的模板名称,无需修改
BK_CI_DISPATCH_THIRD_AGENT_WORKER_ERROR_TEMPLATE=THIRD_AGENT_WORKER_ERROR

##########
# 5-api port
##########
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.tencent.devops.auth.api.oauth2

import com.tencent.devops.auth.pojo.Oauth2AccessTokenRequest
import com.tencent.devops.auth.pojo.dto.ClientDetailsDTO
import com.tencent.devops.auth.pojo.dto.Oauth2AuthorizationCodeDTO
import com.tencent.devops.auth.pojo.vo.Oauth2AccessTokenVo
import com.tencent.devops.auth.pojo.vo.Oauth2AuthorizationInfoVo
Expand All @@ -13,6 +14,7 @@ import io.swagger.v3.oas.annotations.tags.Tag
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import javax.ws.rs.Consumes
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.HeaderParam
import javax.ws.rs.POST
Expand Down Expand Up @@ -70,9 +72,9 @@ interface Oauth2ServiceEndpointResource {
clientSecret: String,
@Parameter(description = "oauth2获取token请求报文体", required = true)
accessTokenRequest: Oauth2AccessTokenRequest
): Result<Oauth2AccessTokenVo?>
): Result<Oauth2AccessTokenVo>

@POST
@GET
@Path("/verifyAccessToken")
@Operation(summary = "校验accessToken")
fun verifyAccessToken(
Expand All @@ -86,4 +88,21 @@ interface Oauth2ServiceEndpointResource {
@Parameter(description = "access token", required = true)
accessToken: String
): Result<String>

@POST
@Path("/createClientDetails")
@Operation(summary = "新增Oauth2客户端信息")
fun createClientDetails(
@Parameter(description = "Oauth2客户端请求实体", required = true)
clientDetailsDTO: ClientDetailsDTO
): Result<Boolean>

@DELETE
@Path("/deleteClientDetails")
@Operation(summary = "删除Oauth2客户端信息")
fun deleteClientDetails(
@Parameter(description = "客户端ID", required = true)
@QueryParam("clientId")
clientId: String
): Result<Boolean>
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package com.tencent.devops.auth.pojo

import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.tencent.devops.auth.pojo.enum.Oauth2GrantType
import io.swagger.v3.oas.annotations.media.Schema

@Schema(title = "oauth2获取token请求报文体")
data class Oauth2AccessTokenRequest(
@get:Schema(title = "授权类型", required = true)
val grantType: String,
@get:Schema(title = "授权码,用于授权码模式", required = false)
val code: String? = null,
@get:Schema(title = "refreshToken,用于刷新授权码模式", required = false)
val refreshToken: String? = null
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "grantType",
visible = true,
defaultImpl = Oauth2AccessTokenRequest::class
)
@JsonSubTypes(
JsonSubTypes.Type(value = Oauth2AuthorizationCodeRequest::class, name = Oauth2AuthorizationCodeRequest.TYPE),
JsonSubTypes.Type(value = Oauth2PassWordRequest::class, name = Oauth2PassWordRequest.TYPE),
JsonSubTypes.Type(value = Oauth2RefreshTokenRequest::class, name = Oauth2RefreshTokenRequest.TYPE)
)
interface Oauth2AccessTokenRequest {
@get:Schema(title = "授权类型", required = true)
open val grantType: Oauth2GrantType
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.tencent.devops.auth.pojo

import com.tencent.devops.auth.pojo.enum.Oauth2GrantType
import io.swagger.v3.oas.annotations.media.Schema

@Schema(title = "授权码模式获取token请求报文体")
data class Oauth2AuthorizationCodeRequest(
@get:Schema(title = "授权类型", required = true)
override val grantType: Oauth2GrantType,
@get:Schema(title = "授权码,用于授权码模式", required = false)
val code: String
) : Oauth2AccessTokenRequest {
companion object {
const val TYPE = "AUTHORIZATION_CODE"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.tencent.devops.auth.pojo

import com.tencent.devops.auth.pojo.enum.Oauth2GrantType
import io.swagger.v3.oas.annotations.media.Schema

@Schema(title = "密码模式获取token请求报文体")
data class Oauth2PassWordRequest(
@get:Schema(title = "授权类型", required = true)
override val grantType: Oauth2GrantType,
@get:Schema(title = "账号名称,用于密码模式", required = false)
val userName: String? = null,
@get:Schema(title = "密码,用于密码模式", required = false)
val passWord: String? = null
) : Oauth2AccessTokenRequest {
companion object {
const val TYPE = "PASS_WORD"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.tencent.devops.auth.pojo

import com.tencent.devops.auth.pojo.enum.Oauth2GrantType
import io.swagger.v3.oas.annotations.media.Schema

@Schema(title = "客户端模式获取token请求报文体")
data class Oauth2RefreshTokenRequest(
@get:Schema(title = "授权类型", required = true)
override val grantType: Oauth2GrantType,
@get:Schema(title = "刷新码,用于刷新授权码模式", required = false)
val refreshToken: String
) : Oauth2AccessTokenRequest {
companion object {
const val TYPE = "REFRESH_TOKEN"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.tencent.devops.auth.pojo.dto

import com.tencent.devops.auth.pojo.enum.Oauth2GrantType
import io.swagger.v3.oas.annotations.media.Schema

@Schema(title = "Oauth2客户端请求实体")
Expand All @@ -15,15 +16,15 @@ data class ClientDetailsDTO(
@get:Schema(title = "图标")
val icon: String,
@get:Schema(title = "授权模式")
val authorizedGrantTypes: String,
val authorizedGrantTypes: List<Oauth2GrantType>,
@get:Schema(title = "跳转链接")
val webServerRedirectUri: String,
@get:Schema(title = "access_token有效时间")
val accessTokenValidity: Long,
@get:Schema(title = "refresh_token有效时间")
val refreshTokenValidity: Long,
@get:Schema(title = "创建人")
val createUser: String? = null,
val createUser: String = "system",
@get:Schema(title = "更新人")
val updateUser: String? = null
val updateUser: String = "system"
)
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ data class Oauth2AccessTokenDTO(
val expiredTime: Long? = null,
@get:Schema(title = "accessToken绑定的用户名称", required = true)
val userName: String? = null,
@get:Schema(title = "accessToken绑定的密码", required = true)
val passWord: String? = null,
@get:Schema(title = "授权范围Id", required = true)
val scopeId: Int
)
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ enum class Oauth2GrantType(val grantType: String) {
// 客户端模式
CLIENT_CREDENTIALS("client_credentials"),

// 密码模式
PASS_WORD("pass_word"),

// 刷新token模式
REFRESH_TOKEN("refresh_token");
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ class AuthOauth2AccessTokenDao {
accessToken: String? = null,
refreshToken: String? = null,
userName: String? = null,
passWord: String? = null,
grantType: String? = null
): TAuthOauth2AccessTokenRecord? {
return with(TAuthOauth2AccessToken.T_AUTH_OAUTH2_ACCESS_TOKEN) {
dslContext.selectFrom(this)
.where(CLIENT_ID.eq(clientId))
.apply { accessToken?.let { and(ACCESS_TOKEN.eq(it)) } }
.apply { userName?.let { and(USER_NAME.eq(it)) } }
.apply { passWord?.let { and(PASS_WORD.eq(it)) } }
.apply { grantType?.let { and(GRANT_TYPE.eq(it)) } }
.apply { refreshToken?.let { and(REFRESH_TOKEN.eq(it)) } }
.fetchOne()
Expand All @@ -43,6 +45,7 @@ class AuthOauth2AccessTokenDao {
dslContext: DSLContext,
clientId: String,
userName: String?,
passWord: String?,
grantType: String,
accessToken: String,
refreshToken: String? = null,
Expand All @@ -54,6 +57,7 @@ class AuthOauth2AccessTokenDao {
this,
CLIENT_ID,
USER_NAME,
PASS_WORD,
GRANT_TYPE,
ACCESS_TOKEN,
REFRESH_TOKEN,
Expand All @@ -62,6 +66,7 @@ class AuthOauth2AccessTokenDao {
).values(
clientId,
userName,
passWord,
grantType,
accessToken,
refreshToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class AuthOauth2ClientDetailsDao {
clientDetailsDTO.clientName,
clientDetailsDTO.scope,
clientDetailsDTO.icon,
clientDetailsDTO.authorizedGrantTypes,
clientDetailsDTO.authorizedGrantTypes.map { it.grantType }.joinToString { "," },
clientDetailsDTO.webServerRedirectUri,
clientDetailsDTO.accessTokenValidity,
clientDetailsDTO.refreshTokenValidity,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@ package com.tencent.devops.auth.resources

import com.tencent.devops.auth.api.oauth2.Oauth2ServiceEndpointResource
import com.tencent.devops.auth.pojo.Oauth2AccessTokenRequest
import com.tencent.devops.auth.pojo.dto.ClientDetailsDTO
import com.tencent.devops.auth.pojo.dto.Oauth2AuthorizationCodeDTO
import com.tencent.devops.auth.pojo.vo.Oauth2AccessTokenVo
import com.tencent.devops.auth.pojo.vo.Oauth2AuthorizationInfoVo
import com.tencent.devops.auth.service.oauth2.Oauth2ClientService
import com.tencent.devops.auth.service.oauth2.Oauth2EndpointService
import com.tencent.devops.common.api.pojo.Result
import com.tencent.devops.common.web.RestResource

@RestResource
class Oauth2ServiceEndpointResourceImpl constructor(
private val endpointService: Oauth2EndpointService
class Oauth2ServiceEndpointResourceImpl(
private val endpointService: Oauth2EndpointService,
private val clientService: Oauth2ClientService
) : Oauth2ServiceEndpointResource {
override fun getAuthorizationInformation(
userId: String,
Expand Down Expand Up @@ -47,7 +50,7 @@ class Oauth2ServiceEndpointResourceImpl constructor(
clientId: String,
clientSecret: String,
accessTokenRequest: Oauth2AccessTokenRequest
): Result<Oauth2AccessTokenVo?> {
): Result<Oauth2AccessTokenVo> {
return Result(
endpointService.getAccessToken(
clientId = clientId,
Expand All @@ -70,4 +73,18 @@ class Oauth2ServiceEndpointResourceImpl constructor(
)
)
}

override fun createClientDetails(clientDetailsDTO: ClientDetailsDTO): Result<Boolean> {
return Result(
clientService.createClientDetails(
clientDetailsDTO = clientDetailsDTO
)
)
}

override fun deleteClientDetails(clientId: String): Result<Boolean> {
return Result(
clientService.deleteClientDetails(clientId = clientId)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ package com.tencent.devops.auth.service.oauth2
import com.tencent.devops.auth.constant.AuthMessageCode
import com.tencent.devops.auth.dao.AuthOauth2AccessTokenDao
import com.tencent.devops.common.api.exception.ErrorCodeException
import com.tencent.devops.common.api.util.AESUtil
import com.tencent.devops.model.auth.tables.records.TAuthOauth2AccessTokenRecord
import org.jooq.DSLContext
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service

@Service
class Oauth2AccessTokenService constructor(
class Oauth2AccessTokenService(
private val oauth2AccessTokenDao: AuthOauth2AccessTokenDao,
private val dslContext: DSLContext
) {
@Value("\${aes.auth:#{null}}")
private val aesKey = ""

fun get(
clientId: String,
accessToken: String
Expand All @@ -31,13 +36,15 @@ class Oauth2AccessTokenService constructor(
clientId: String,
refreshToken: String? = null,
userName: String? = null,
passWord: String? = null,
grantType: String? = null
): TAuthOauth2AccessTokenRecord? {
return oauth2AccessTokenDao.get(
dslContext = dslContext,
clientId = clientId,
refreshToken = refreshToken,
userName = userName,
passWord = passWord?.let { AESUtil.encrypt(aesKey, passWord) },
grantType = grantType
)
}
Expand All @@ -46,6 +53,7 @@ class Oauth2AccessTokenService constructor(
fun create(
clientId: String,
userName: String?,
passWord: String?,
grantType: String,
accessToken: String,
refreshToken: String?,
Expand All @@ -56,6 +64,7 @@ class Oauth2AccessTokenService constructor(
dslContext = dslContext,
clientId = clientId,
userName = userName,
passWord = passWord?.let { AESUtil.encrypt(aesKey, passWord) },
grantType = grantType,
accessToken = accessToken,
refreshToken = refreshToken,
Expand Down
Loading

0 comments on commit e1b68e6

Please sign in to comment.