Class GoogleGroupsSecurityRealm
- All Implemented Interfaces:
ExtensionPoint,Describable<SecurityRealm>
The standard Jenkins login page is kept: its username/password form is checked against
the HudsonPrivateSecurityRealm.Details property stored on existing local user
records (created under the local-database realm), which is the break-glass path if Google
OAuth is down or misconfigured. GoogleFederatedLoginService adds the
"Sign in with Google" button underneath that form.
Google user id = full email (lowercase), bound to the Google account's stable sub
on first login (GoogleAccountProperty). Authorities are re-resolved at each Google
login and live for the session; API-token requests get the authorities recorded at the
user's last Google login via LastGrantedAuthoritiesProperty, but only for
getGroupAuthorityMaxAgeDays() days, because Jenkins cannot see later removals from
Google Groups or from the Workspace.
Pre-existing local users' API tokens keep working because token authentication checks
stored user records independent of this realm.
-
Nested Class Summary
Nested ClassesNested classes/interfaces inherited from class hudson.security.SecurityRealm
SecurityRealm.SecurityComponentsNested classes/interfaces inherited from interface hudson.ExtensionPoint
ExtensionPoint.LegacyInstancesAreScopedToHudson -
Field Summary
Fields inherited from class hudson.security.SecurityRealm
AUTHENTICATED_AUTHORITY, AUTHENTICATED_AUTHORITY2, LIST, NO_AUTHENTICATION -
Constructor Summary
ConstructorsConstructorDescriptionGoogleGroupsSecurityRealm(String clientId, Secret clientSecret, String hostedDomain) -
Method Summary
Modifier and TypeMethodDescriptionbooleanprotected org.springframework.security.core.userdetails.UserDetailsauthenticate2(String username, String password) Break-glass password login on the standard Jenkins login form: checks the candidate password against theHudsonPrivateSecurityRealm.Detailsproperty stored on the user record (present on users created under the local-database realm).org.kohsuke.stapler.HttpResponsedoCommenceLogin(org.kohsuke.stapler.StaplerRequest2 request, String from, String referer) Starts the OAuth code flow.org.kohsuke.stapler.HttpResponsedoFinishLogin(org.kohsuke.stapler.StaplerRequest2 request, String code, String state, String error) OAuth redirect URI.intHow many days the group authorities recorded at a user's last Google login stay valid for API-token requests.loadGroupByGroupname2(String groupname, boolean fetchMembers) Accepts any well-formed group email.org.springframework.security.core.userdetails.UserDetailsloadUserByUsername2(String username) Returns the user if a Jenkins user record exists — this keeps API-token users resolvable and lets authorization strategies validate names.voidsetGroupAuthorityMaxAgeDays(int groupAuthorityMaxAgeDays) voidsetGroupIncludePattern(String groupIncludePattern) voidsetOnGroupLookupFailure(GroupLookupFailurePolicy onGroupLookupFailure) Methods inherited from class hudson.security.AbstractPasswordBasedSecurityRealm
authenticate, authenticateByPassword, createSecurityComponents, loadGroupByGroupname, loadUserByUsernameMethods inherited from class hudson.security.SecurityRealm
all, canLogOut, commenceSignup, commonFilters, createCliAuthenticator, createFilter, createFilter, doCaptcha, doLogout, doLogout, getAuthenticationGatewayUrl, getCaptchaSupport, getCaptchaSupportDescriptors, getDescriptor, getFrom, getGroupIdStrategy, getLoginUrl, getPostLogOutUrl, getPostLogOutUrl2, getPostLogOutUrl2, getSecurityComponents, getUserIdStrategy, loadGroupByGroupname, setCaptchaSupport, validateCaptcha
-
Constructor Details
-
GoogleGroupsSecurityRealm
-
-
Method Details
-
getClientId
-
getClientSecret
-
getHostedDomain
-
getGroupIncludePattern
-
setGroupIncludePattern
-
getOnGroupLookupFailure
-
setOnGroupLookupFailure
@DataBoundSetter public void setOnGroupLookupFailure(@NonNull GroupLookupFailurePolicy onGroupLookupFailure) -
getGroupAuthorityMaxAgeDays
public int getGroupAuthorityMaxAgeDays()How many days the group authorities recorded at a user's last Google login stay valid for API-token requests. Jenkins never re-checks Google between logins, so without a limit someone removed from a group (or from the Workspace) keeps that group's permissions through their API tokens indefinitely. After expiry, token requests carry onlyauthenticateduntil the user signs in with Google again.0disables expiry. Sessions are not affected; they end with the normal session timeout. -
setGroupAuthorityMaxAgeDays
@DataBoundSetter public void setGroupAuthorityMaxAgeDays(int groupAuthorityMaxAgeDays) -
allowsSignup
public boolean allowsSignup()- Overrides:
allowsSignupin classSecurityRealm
-
authenticate2
protected org.springframework.security.core.userdetails.UserDetails authenticate2(String username, String password) throws org.springframework.security.core.AuthenticationException Break-glass password login on the standard Jenkins login form: checks the candidate password against theHudsonPrivateSecurityRealm.Detailsproperty stored on the user record (present on users created under the local-database realm). Users without a stored password — i.e. everyone who only ever logged in via Google — cannot log in by password at all.- Overrides:
authenticate2in classAbstractPasswordBasedSecurityRealm- Throws:
org.springframework.security.core.AuthenticationException
-
loadUserByUsername2
public org.springframework.security.core.userdetails.UserDetails loadUserByUsername2(String username) throws org.springframework.security.core.userdetails.UsernameNotFoundException Returns the user if a Jenkins user record exists — this keeps API-token users resolvable and lets authorization strategies validate names. Authorities come from the last interactive login (LastGrantedAuthoritiesProperty), so API-token requests carry the user's group authorities too, untilgetGroupAuthorityMaxAgeDays()days after their last Google login. Local users (noGoogleAccountProperty) never expire: their access comes fromuser:grants, not Google Groups.- Overrides:
loadUserByUsername2in classAbstractPasswordBasedSecurityRealm- Throws:
org.springframework.security.core.userdetails.UsernameNotFoundException
-
loadGroupByGroupname2
public GroupDetails loadGroupByGroupname2(String groupname, boolean fetchMembers) throws org.springframework.security.core.userdetails.UsernameNotFoundException Accepts any well-formed group email. We cannot enumerate or validate groups server-side in user-token mode, so this never makes a directory call.- Overrides:
loadGroupByGroupname2in classAbstractPasswordBasedSecurityRealm- Throws:
org.springframework.security.core.userdetails.UsernameNotFoundException
-
doCommenceLogin
public org.kohsuke.stapler.HttpResponse doCommenceLogin(org.kohsuke.stapler.StaplerRequest2 request, @QueryParameter String from, @Header("Referer") String referer) throws IOException Starts the OAuth code flow. Reached by the "Sign in with Google" link, so it must accept GET and anonymous callers. Its only effect is storing a freshstateand PKCE verifier in the caller's own session; forcing a victim here merely restarts their login.- Throws:
IOException
-
doFinishLogin
public org.kohsuke.stapler.HttpResponse doFinishLogin(org.kohsuke.stapler.StaplerRequest2 request, @QueryParameter String code, @QueryParameter String state, @QueryParameter String error) throws IOException OAuth redirect URI. Google redirects the browser here with a GET request (RFC 6749 section 4.1.2) before the user is logged in, so neither POST nor a permission check is possible. CSRF protection is the OAuthstateparameter, which must match the single-use value stored in the caller's session, plus PKCE; the token request to Google's fixed endpoint only happens after that check.- Throws:
IOException
-