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

feat:oauth2 增加密码模式 #10663 #10703

Merged
merged 14 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

密码需要加密存储

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
Loading