1. 程式人生 > >Pac4j文件翻譯(3.0)

Pac4j文件翻譯(3.0)

翻譯有很多不準確的地方,只作為自己學習的筆記來用。歡迎批評指正。

Pac4j簡介

pac4j是一個簡單而強大的安全引擎,用於Java對使用者進行身份驗證、獲取其配置檔案和管理授權,以確保web應用程式安全。它提供了一套完整的概念和元件。它基於Java 8,並在Apache 2許可下使用。它可用於大多數框架/工具和支援大多數認證/授權機制。

1. 主要概念和元件介紹

  • 1) client(客戶端): 客戶端表示身份驗證機制(流)。它執行登入過程並返回一個使用者概要檔案。間接客戶端用於UI身份驗證,而直接客戶端則用於web服務身份驗證。

  • 2) authenticator(認證器):HTTP客戶端驗證憑證需要一個認證器。它是ProfileService的一個子元件,該元件驗證憑證,同時也處理使用者的建立、更新和移除操作。

  • 3) authorizer(授權器):授權器用於檢查已認證使用者的授權或當前web上下文中的授權。

  • 4) matcher(匹配器):一個匹配器定義了security是否必須應用到安全過濾器。

  • 5) config(配置):配置通過客戶端、授權器和匹配器定義安全配置。

  • 6) user profile(使用者概要檔案):使用者概要是已認證使用者的概要。它有一個識別符號、屬性、角色、許可權、一個“記住-我”屬性和一個連結識別符號。

  • 7) web context(web上下文):web上下文是對pac4j實現特有的HTTP請求和響應的抽象,而關聯的SessionStore表示會話的實現。

  • 8) security filter(安全過濾器):(或者不論使用什麼原理去攔截的HTTP請求)根據客戶端和授權配置,通過檢查使用者已認證和已授權來保護一個URL。如果使用者沒有被認證,它對直接客戶端展示認證,對間接客戶端啟動登入程序。

  • 9) callback controller(回撥控制器):對間接客戶端結束登入程序後的回撥。

  • 10) logout controller(退出登入控制器):處理應用程式和/或身份伺服器登出。

2 認證機制

client支援多種認證機制:OAuth、SAML、CAS、OpenID Connect、HTTP、OpenID、Google APP Engine、Kerberos(SPNEGO)

Authenticators:LDAP、SQL、JWT、MongoDB、CouchDB、IP address、REST API

通常,授權器被定義在應用的安全配置檔案中。有不同的授權器變數如下:

Roles/permissions - Anonymous/remember-me/(fully) authenticated - Profile type, attribute

CORS - CSRF - Security headers - IP address, HTTP method

大多數pac4j元件實現DefaultAuthorizationChecker元件來使用pac4j的邏輯和授權。因此,下列授權器可以通過短名稱自動找到:

  • hsts:StrictTransportSecurityHeader 認證器
  • nosniff: XContentTypeOptionsHeader 認證器
  • noframe: XFrameOptionsHeader 認證器
  • xssprotection: XSSProtectionHeader 認證器
  • nocache: CacheControlHeader 認證器
  • securityheaders: as a shortcut for hsts,nosniff,noframe,xssprotection,nocache
  • csrfToken: CsrfTokenGeneratorAuthorizer 認證器
  • csrfCheck: CsrfAuthorizer 認證器
  • csrf as a shortcut for csrfToken,csrfCheck
  • isAnonymous:IsAnonymousAuthorizer 認證器
  • isAuthenticated:IsAuthenticatedAuthorizer 認證器
  • isFullyAuthenticated:IsFullyAuthenticatedAuthorizer 認證器
  • isRemembered: IsRememberedAuthorizer 認證器
  • allowAjaxRequests for a default configuration of the CorsAuthorizer authorizer with the Access-Control-Allow-Origin header set to *.

這些短名稱都作為常量定義在DefaultAuthorizers類中。

4 Matchers 匹配器

1) 定義(definition)

pac4j提供了一個安全模型和引擎(特定的行為)。安全過濾器負責url保護、請求認證和可選授權。

在某些情況下,你可能想要繞開安全過濾器(security filter)。而使用匹配器引數(matchers parameter)可以做到,引數通常是一個匹配名稱的列表。一個匹配器通常定義在安全配置檔案中(security configuration)。

2) 實現(implementation)

一個匹配器可以通過實現Matcher介面來定義。它只有一個方法:

boolean matches(WebContext context);

這個方法表明安全過濾器(security filter)是否必須被應用。

一些預設的matcher匹配器可以用。(但是你可以開發自己的匹配器):
- PathMatcher:允許你從安全檢查中排除一些路徑。
- HeaderMatcher:允許你檢查一個給出的頭部是否是空或匹配一個特定的表示式。
- HttpMethodMatcher:允許你檢查HTTP請求的方法是否是你預期的已定義的方法之一。

5 Security configuration 安全配置

1) 配置元件
大多數pac4j實現中,安全配置可以通過配置物件去定義。

它有這些必須的:
- PasswordEncoders:密碼加密器
- Authenticators:認證器
- Clients:客戶端
- Authorizers:授權器
- Matchers:匹配器

例如:

Config 1

FacebookClient facebookClient = new FacebookClient("145278422258960", "be21409ba8f39b5dae2a7de525484da8");
TwitterClient twitterClient = new TwitterClient("CoxUiYwQOSFDReZYdjigBA", "2kAzunH5Btc4gRSaMr7D7MkyoJ5u1VzbOOzE8rBofs");
ParameterClient parameterClient = new ParameterClient("token", new JwtAuthenticator(salt));

Config config = new Config("http://localhost:8080/callback", facebookClient, twitterClient, parameterClient);

config.addAuthorizer("admin", new RequireAnyRoleAuthorizer<>("ROLE_ADMIN"));
config.addAuthorizer("custom", new CustomAuthorizer());

config.addMatcher("excludedPath", new ExcludedPathMatcher("^/facebook/notprotected\\.jsp$"));

您還可以使用一箇中間客戶端物件來構建Config 1。例如Config 2

Config 2

Clients clients = new Clients("http://localhost:8080/callback", facebookClient, twitterClient, parameterClient);

Config config = new Config(clients);

在上面的例子中,你可以為所有的客戶端定義這些內容:

  • 一個回撥地址(callback URL)和一個回撥地址解析器(CallbackUrlResolver):
clients.setCallbackUrl(callbackUrl); 

clients.setCallbackUrlResolver(callbackUrlResolver);
  • 一個非同步請求解析器(AjaxRequestResolver):
clients.setAjaxRequestResolver(ajaxRequestResolver);
  • 一個認證生成器(AuthorizationGenerator):
clients.addAuthorizationGenerator(authorizationGenerator);

2) pac4j-config module(pac4j配置模組)
pac4j-config模組收集所有pac4j工具來定義這個配置物件。當前,只有一個元件允許你從一系列屬性中建立客戶端:PropertiesConfigFactory. Dropwizard, CAS 和 Knox用到該類。

注意:當需要的時候,這些依賴必須被明確宣告。(如果你想要使用SAML、OAuth…)

例如:

pac4j:
  callbackUrl: /callback
  clientsProperties:
    facebook.id: 145278422258960
    facebook.secret: be21409ba8f39b5dae2a7de525484da8
    saml.keystorePath: resource:samlKeystore.jks
    saml.keystorePassword: pac4j-demo-passwd
    saml.privateKeyPassword: pac4j-demo-passwd
    saml.identityProviderMetadataPath: resource:metadata-okta.xml
    saml.maximumAuthenticationLifetime: 3600
    saml.serviceProviderEntityId: http://localhost:8080/callback?client_name=SAML2Client
    saml.serviceProviderMetadataPath: sp-metadata.xml
    anonymous: fakevalue
    ldap.type: direct
    ldap.url: ldap://ldap.jumpcloud.com:389
    ldap.useStartTls: false
    ldap.useSsl: false
    ldap.dnFormat: uid=%s,ou=Users,o=58e69adc0914b437324e7632,dc=jumpcloud,dc=com
    ldap.usersDn: ou=Users,o=58e69adc0914b437324e7632,dc=jumpcloud,dc=com
    ldap.principalAttributeId: uid
    ldap.principalAttributes: firstName,lastName
    ldap.enhanceWithEntryResolver: false
    formClient.loginUrl: /login.html
    formClient.authenticator: ldap

下面是一項你可以來定義客戶端(,密碼加密器和認證器)的一些屬性:

可用屬性 用法
encoder.spring.type (bcrypt, noop, pbkdf2, scrypt or standard), encoder.spring.bcrypt.length, encoder.spring.pbkdf2.secret, encoder.spring.pbkdf2.iterations, encoder.spring.pbkdf2.hashWidth, encoder.spring.scrypt.cpuCost, encoder.spring.scrypt.memoryCost, encoder.spring.scrypt.parallelization, encoder.spring.scrypt.keyLength, encoder.spring.scrypt.saltLength and encoder.spring.standard.secret 根據所提供的屬性和命名的編碼器定義一個SpringPasswordEncoder。
encoder.shiro (if no specific properties are required), encoder.shiro.generatePublicSalt, encoder.shiro.hashAlgorithmName, encoder.shiro.hashIterations and encoder.shiro.privateSalt 根據所提供的屬性和命名的編碼器定義一個ShiroPasswordEncoder。
ldap.type, ldap.dnFormat, ldap.principalAttributes,ldap.principalAttributeId, ldap.principalAttributePassword, ldap.subtreeSearch, ldap.usersDn, ldap.userFilter, ldap.enhanceWithEntryResolver, ldap.trustCertificates, ldap.keystore, ldap.keystorePassword, ldap.keystoreType, ldap.minPoolSize, ldap.maxPoolSize, ldap.poolPassivator, ldap.validateOnCheckout, ldap.validatePeriodically, ldap.validatePeriod, ldap.failFast, ldap.idleTime, ldap.prunePeriod, ldap.blockWaitTime, ldap.url, ldap.useSsl, ldap.useStartTls, ldap.connectTimeout, ldap.providerClass, ldap.allowMultipleDns, ldap.bindDn, ldap.bindCredential, ldap.saslRealm, ldap.saslMechanism, ldap.saslAuthorizationId, ldap.saslSecurityStrength and ldap.saslQualityOfProtection 根據所提供的屬性和命名ldap或ldap來定義LdapAuthenticator。
db.dataSourceClassName, db.jdbcUrl, db.userAttributes, db.userIdAttribute, db.usernameAttribute, db.userPasswordAttribute, db.usersTable, db.username, db.password, db.autoCommit, db.connectionTimeout, db.idleTimeout, db.maxLifetime, db.connectionTestQuery, db.minimumIdle, db.maximumPoolSize, db.poolName, db.initializationFailTimeout, db.isolateInternalQueries, db.allowPoolSuspension, db.readOnly, db.registerMbeans, db.catalog, db.connectionInitSql, db.driverClassName, db.transactionIsolation, db.validationTimeout, db.leakDetectionThreshold, db.customParamKey, db.customParamValue, db.loginTimeout, db.dataSourceJndi and db.passwordEncoder 要基於所提供的屬性定義DbAuthenticator,並命名為db或db.N
rest.url 按照所提供的屬性和命名rest或rest.n來定義RestAuthenticator
anonymous 定義AnonymousClient,該值將被忽略
directBasicAuth.authenticator 根據所提供的屬性定義DirectBasicAuthClient
saml.keystorePassword, saml.privateKeyPassword, saml.keystorePath, saml.identityProviderMetadataPath, saml.maximumAuthenticationLifetime, saml.serviceProviderEntityId, saml.serviceProviderMetadataPath, saml.destinationBindingType, saml.keystoreAlias 根據所提供的屬性定義SAML2Client
cas.loginUrl, cas.protocol 根據所提供的屬性來定義CasClient
oidc.type (google or azure), oidc.id, oidc.secret, oidc.scope, oidc.discoveryUri, oidc.useNonce, oidc.preferredJwsAlgorithm, oidc.maxClockSkew, oidc.clientAuthenticationMethod, oidc.customParamKey1, oidc.customParamValue1, oidc.customParamKey2,oidc.customParamValue2 根據所提供的屬性定義OpenID connect client
formClient.authenticator, formClient.loginUrl, formClient.usernameParameter formClient.passwordParameter 根據所提供的屬性定義FormClient
indirectBasicAuth.authenticator, indirectBasicAuth.realName 根據所提供的屬性定義IndirectBasicAuthClient
facebook.id, facebook.secret, facebook.scope, facebook.fields 基於所提供的屬性定義一個FacebookClient
twitter.id, twitter.secret 根據所提供的屬性來定義TwitterClient
github.id, github.secret 根據所提供的屬性來定義GitHubClient
dropbox.id, dropbox.secret 根據所提供的屬性來定義DropBoxClient
windowslive.id, windowslive.secret 根據所提供的屬性定義windowslivecent
yahoo.id, yahoo.secret 根據所提供的屬性來定義一個YahooClient
linkedin.id, linkedin.secret, linkedin.fields, linkedin.scope 根據所提供的屬性來定義一個LinkedIn2Client
foursquare.id, foursquare.secret 根據所提供的屬性來定義一個FoursquareClient
google.id, google.secret, google.scope 根據所提供的屬性定義一個Google2Client

注意:
- 你可以在屬性末尾新增一個數字來定義多個相同型別的client:cas.loginUrl.2, oidc.type.5
- passwordEncoder屬性必須設定為已定義的passwordEncoder的名稱,如:encoder.spring or encoder.shiro.3
- Authenticator屬性必須設定為已定義的 身份驗證器( Authenticator)的名稱,如: ldap or db.1或者隱含的值:testUsernamePassword or testToken.

6 User profile 使用者概要

當用戶成功通過pac4j進行身份驗證時,他的資料將從身份提供程式中檢索,並構建一個使用者概要。他的概要有:

  • an identifier (getId()):識別符號
  • attributes (getAttributes(), getAttribute(name)):屬性
  • authentication-related attributes (getAuthenticationAttributes(), getAuthenticationAttribute(name)):認證相關屬性
  • roles (getRoles()):角色
  • permissions (getPermissions()):許可權
  • a client name (getClientName()):客戶端名稱
  • a remember-me nature (isRemembered()):記住我的性質
  • a linked identifier (getLinkedId()):連結識別符號

1) Identifier

每個使用者配置檔案必須具有唯一的識別符號。因此,當構建使用者概要檔案時,pac4j客戶端使用的是概要識別符號——從身份提供者那裡執行惟一性的值。

這可以很好地處理來自同一身份提供者的概要檔案,儘管在使用多個身份提供者時這可能會成為一個問題。我們可能在標識提供者中選擇的識別符號之間發生衝突。為了避免這個問題,在檔案識別符號之前新增概要檔案類名,要有一個”型別識別符號”。

例如:

profile.getId() // 00001
profile.getTypedId() // org.pac4j.oauth.profile.facebook.FacebookProfile#00001

2) 屬性

使用者概要檔案具有屬性,這些屬性來自於從身份提供者檢索的資料(在轉換之後)。

3) 認證相關屬性

一些身份提供者將包括與身份驗證本身相關的屬性,比如身份驗證方法、身份驗證有效的時間期限,或關於身份提供者的元資料。這些屬性與使用者的屬性是分開儲存的。

4) 角色和許可權
角色和許可權可以通過addRole(role), addRoles(roles), addPermission(permission) and addPermissions(permissions) 方法新增到使用者概要檔案中。

它們通常是在一個授權生成器(AuthorizationGenerator)中計算的。

5) 客戶端名稱

在登入過程中,客戶端的名稱通過setClientName(name)儲存到使用者概要中,隨後可以通過getClientName()方法檢索到。

6) 記住我
使用者概要可以通過setRemembered(boolean)方法定義為記住我,而不是完全通過認證。isRemember()方法人會使用者概要是否被記住。

7) CommonProfile的通用方法

Method Type Returns
getEmail() String Email 屬性
getFirstName() String first_name 屬性
getFamilyName() String family_name 屬性
getDisplayName() String display_name 屬性
getUsername() String username 屬性
getGender() Gender gender 屬性
getLocale() Locale locale 屬性
getPictureUrl() URI picture_url 屬性
getProfileUrl() URI profile_url 屬性
getLocation() String location 屬性
asPrincipal() Principal 一個包含當前已認證使用者名稱的物件
isExpired() boolean 如果當前配置檔案過期,則為false

8) 配置檔案定義(Profile definition)

配置檔案類和屬性通過實現 ProfileDefinition類來定義。

setProfileFactory方法允許您定義例項類,以便返回給使用者配置檔案,而primary 和 secondary方法允許您用特定的轉換器定義屬性。

許多屬性轉換器以及存在: BooleanConverter, ColorConverter… 檢視包 org.pac4j.core.profile.converter

因此,newProfile方法返回一個新的類例項,而convertAndAdd方法如果有相關的轉換器會轉換屬性,並將它們新增到概要檔案中。

9) 配置層級(Profile hierarchy)

事實上,大多數Client都不會返回一個CommonProfile,而是一個特定的配置,如:FacebookProfile, the OidcProfile…:
- (部分地)用特定的實現覆蓋公共概要的公共方法
- 為他們的特定屬性新增特定的getter。

10) 連結識別符號
每個使用者配置檔案可能有一個連結識別符號,它是另一個使用者配置檔案的識別符號。這種方式,使得兩個使用者配置檔案都被聯絡起來,它允許你通過一個帳戶進行身份驗證,這個使用者可以載入定義在第一個使用者中的連結使用者,特別是通過使用LoadLinkedUserAuthorizationGenerator生成的。

7 會話儲存和儲存(SessionStore and Store)

  1. Session Store

WebContext對於處理HTTP請求和響應是一個抽象的類。為了處理session,它依賴於一個SessionStore,可以通過getSessionStore方法獲得。

SessionStore有如下方法:
- getOrCreateSessionId: 獲取或建立會話識別符號並在必要時用它初始化會話
- get: 從會話中獲取屬性
- set: 給會話設定屬性
- destroySession: 銷燬潛在的web會話
- getTrackableSession: 把本機會話作為可跟蹤物件(用於反向通道登出)
- buildFromTrackableSession: 從可跟蹤的會話(用於反向通道登出)構建一個新的會話
- renewSession: 通過將所有資料複製到一個新的資料來更新本機會話

例如,J2EContext當前使用J2ESessionStore,依賴於J2ESession。在遊戲中,我們有一個特定的基於快取的PlayCacheSessionStore,以及在Knox中有一個基於cookie的KnoxSessionStore。

ProfileStorageDecision定義與該概要檔案相關的決策,通過該決策,我們判斷是否必須將其讀取並儲存到web會話中。它被DefaultSecurityLogic使用:
- DefaultProfileStorageDecision在預設情況下被設定,這對於一個只使用間接客戶端或直接客戶端的web應用程式是適合的。

  1. Store

在某些情況下,需要一個快取機制。在pac4j中,通過Store這個概念定義。

它有如下幾個方法:
- get:從store中獲取一個值
- set:往store中設定一個值
- remove:從store中移除一個值(通過key)

它只有一個使用了Guava的預設實現:GuavaStore。如果需要,你可以提供你自己的一個Store。

8 釋出說明-向後相容性(Release notes - Backward compatibility)

此處略去。。。

9 認證流程-大圖片(Authentication flows - Big picture)

1) UI 認證(有狀態stateful/間接客戶端indirect client):
image
CAS特定的有狀態身份驗證流:
image

2) Web服務認證(無狀態stateless/直接客戶端direct client):
image

  1. Big picture:
    image

10 自定義(customizations)

pac4j為各種需求提供了大量的元件,所以在進行定製之前,您應該仔細閱讀Clients, Authenticators 和 Authorizers頁面,以檢查已經提供的內容。

自定義認證器/授權器元件

確定你清楚的明白不同元件的角色是什麼:
- Client是一個完整的登入過程:間接地用於UI(IndirectClient),直接的用於web服務(DirectClient。它重定向到身份提供者(僅間接客戶端)),提取使用者憑證,驗證使用者憑證,併為經過身份驗證的使用者建立使用者配置檔案。
- RedirectActionBuilder會將使用者重定向到身份提供程式以便登入(間接客戶端)
- CredentialsExtractor從HTTP請求中提取使用者憑證(間接和直接的客戶端)
- Authenticator驗證使用者憑證(間接和直接客戶端)
- ProfileCreator為經過身份驗證的使用者(間接和直接客戶端)建立使用者配置檔案。
- Authorizer允許基於使用者配置檔案或web上下文訪問
- Matcher定義了安全性是否必須應用於web上下文
- 一個AuthorizationGenerator為給定的使用者概要檔案生成適當的角色和許可權。

重寫或建立新元件應該是簡單的。儘管如此,建立客戶端需要額外的努力,需要注意:
- 你需要了解你希望支援哪種身份驗證機制:它是用於UI(憑證只提供一次,身份驗證幾乎總是在外部身份提供程式中發生)或web服務(為每個請求傳遞憑證)
- 所有客戶端都應該實現IndirectClient介面,並定義適當的RedirectActionBuilder, CredentialsExtractor,Authenticator和ProfileCreator (以及可選的LogoutActionBuilder)。
- 它可能需要建立一個新的Credentials型別(如果它不是一個由TokenCredentials設計或UsernamePasswordCredentials設計的使用者名稱/密碼的簡單的字串)。這些新的憑證可能繼承受支援協議的基本憑證(如oauth憑據)
- 為新客戶端建立新概要通常是一種良好的實踐。(不管這個配置檔案是否有特定的資料),以便能夠區分所有使用者配置檔案。新的使用者配置檔案應該從協議支援的基本概要檔案繼承,比如OAuth20Profile。至少,它必須繼承自CommonProfile。身份提供者返回的資料可能需要被轉換(例如,一個單一的字串到Java列舉中),對於這一點,轉換器(類繼承了AttributeConverter的類)是必要的。轉換器和返回的使用者概要類都必須在ProfileDefinition中定義。

改變核心流:
覆蓋或建立新元件允許你在常規pac4j“過濾器”的定義邏輯的邊界內實現新的行為。然而,在某些情況下,這可能還不夠。因此,你可能決定打破流程,通過請求一些額外的操作來改變所提供的行為。這可以通過丟擲HttpAction(如任何異常)來實現,因為大多陣列件都允許這樣做。

例如:

public class ExampleAuthorizer implements Authorizer<CommonProfile> {

    @Override
    public boolean isAuthorized(WebContext context, List<CommonProfile> profiles) throws HttpAction {
        if ("specificValue".equals(context.getRequestHeader("specificHeader")))
        {
            throw HttpAction.redirect("force redirection", context, "/message.html");
        }
        return true;
    }
}

自定義web整合

pac4j實現嚴重依賴於WebContext和SessionStore來處理HTTP請求、響應和會話。這些元件的預設實現可能會被覆蓋或替換。除了預設的ProfileManager(用於儲存/恢復概要檔案)或GuavaStore(在快取中儲存資料)。在所有情況下,沒有什麼比檢視現有元件作為示例更好的了。請不要猶豫,在pac4j dev郵件列表上問任何問題。

11 第三方擴充套件

對於由第三方開發的pac4j,有一些擴充套件。擴充套件提供了核心pac4j發行版中不可用的特性,這些特性可能對特定的使用者有特定的需求是有用的。目前,以下副檔名是已知的:

IDC 擴充套件

IDC Extensions to PAC4J是IDC內部開發的一個專案,並以開源的形式釋出。它提供瞭如下模組:
- SAML客戶端的資料庫配置-這個模組允許你使用關係資料庫配置一系列SAML2客戶端,例如Oracle資料庫。你不需要改變你的PAC4J靜態配置(例如spring xml file)就能使應用的配置發生改變。你只需向資料庫表中新增一行或修改現有行,然後重新啟動你的應用程式即可。你也可以實現一個重新載入機制,允許你在不重啟應用程式的情況下進行配置更改。

12 JavaDoc