Documentation
¶
Overview ¶
Package auth provides authentication utilities for CERN SSO.
Package auth provides authentication utilities for CERN SSO.
Index ¶
- Constants
- Variables
- func AuthorizationCodeFlow(kerbClient *KerberosClient, cfg OIDCConfig) (string, error)
- func Check2FARequired(body string) bool
- func CheckConsentRequired(body string) bool
- func ConvertAPICacheToFile() (string, error)
- func ConvertSpecificCacheToFile(cacheInfo *CacheInfo) (string, error)
- func FindCCachePath() string
- func GetCurrentMethod(body string) string
- func GetErrorMessage(doc *goquery.Document) string
- func GetErrorMessageFromHTML(r io.Reader) (string, error)
- func GetPrincipalFromKlist() (string, error)
- func HasTryAnotherWay(body string) bool
- func IsMacOSAPICCache() bool
- func IsOTPRequired(body string) bool
- func IsRefreshable(source string) bool
- func IsWebAuthnAvailable() bool
- func IsWebAuthnRequired(body string) bool
- func LoadKrb5Config(source string) (*config.Config, error)
- func NewClientFromCCache(cfg *config.Config) (*client.Client, error)
- func NormalizePrincipal(username string) string
- func ParseForm(r io.Reader) (action string, data url.Values, err error)
- func ParseGitLabOIDCForm(r io.Reader) (action string, data url.Values, err error)
- func ParseKerberosLink(r io.Reader, authHostname string) (string, error)
- func ParseSAMLForm(r io.Reader) (action string, data url.Values, err error)
- func PostSAML(client *http.Client, action string, data url.Values) (*http.Response, error)
- type AuthMethod
- type CacheInfo
- type KerberosClient
- func (k *KerberosClient) Close()
- func (k *KerberosClient) CollectCookies(targetURL string, authHostname string, result *LoginResult) ([]*http.Cookie, error)
- func (k *KerberosClient) DoSPNEGO(targetURL string) (*http.Response, error)
- func (k *KerberosClient) DoSPNEGORequest(req *http.Request) (*http.Response, error)
- func (k *KerberosClient) GetCollectedCookies() []*http.Cookie
- func (k *KerberosClient) GetCookies(u *url.URL) []*http.Cookie
- func (k *KerberosClient) GetHTTPClient() *http.Client
- func (k *KerberosClient) LoginWithKerberos(loginPage string, authHostname string, verifyCert bool) (*LoginResult, error)
- func (k *KerberosClient) SetOTPProvider(provider *OTPProvider)
- func (k *KerberosClient) SetPreferredMethod(method string)
- func (k *KerberosClient) SetWebAuthnProvider(provider *WebAuthnProvider)
- func (k *KerberosClient) TryLoginWithCookies(targetURL string, authHostname string, cookies []*http.Cookie) (*LoginResult, error)
- type LoginError
- type LoginResult
- type MethodSelectionPage
- type OIDCConfig
- type OTPForm
- type OTPProvider
- type TokenResponse
- type TryAnotherWayForm
- type WebAuthnForm
- type WebAuthnProvider
- type WebAuthnResult
Constants ¶
const ( Krb5ConfigEmbedded = "embedded" Krb5ConfigSystem = "system" )
Krb5ConfigSource constants for config source options.
const ( OTPSourceFlag = "flag" OTPSourceCommand = "command" OTPSourceEnv = "env" OTPSourcePrompt = "prompt" )
OTP source priority constants
const ( EnvOTP = "CERN_SSO_OTP" EnvOTPCommand = "CERN_SSO_OTP_COMMAND" )
Environment variable names for OTP configuration
const ( MethodOTP = "otp" MethodWebAuthn = "webauthn" )
2FA method preference constants
const ( WebAuthnSourceDevice = "device" WebAuthnSourceBrowser = "browser" )
WebAuthn source constants
const (
EnvWebAuthnPIN = "CERN_SSO_WEBAUTHN_PIN"
)
Environment variable names for WebAuthn configuration
Variables ¶
var ErrLoginFailed = errors.New("login failed")
ErrLoginFailed represents a login failure.
Functions ¶
func AuthorizationCodeFlow ¶
func AuthorizationCodeFlow(kerbClient *KerberosClient, cfg OIDCConfig) (string, error)
AuthorizationCodeFlow performs the OAuth2 Authorization Code flow with Kerberos.
func Check2FARequired ¶
Check2FARequired checks if the response requires 2FA.
func CheckConsentRequired ¶
CheckConsentRequired checks if consent is required.
func ConvertAPICacheToFile ¶
ConvertAPICacheToFile attempts to convert macOS API credential cache to a file-based cache. Uses kinit --keychain to get tickets from keychain-stored password. Returns the path to the created file cache, or error if conversion fails.
func ConvertSpecificCacheToFile ¶
ConvertSpecificCacheToFile converts a specific macOS API cache to a file-based cache. Uses kgetcred to export the TGT from the specified cache to a file. This allows using a non-default principal without modifying the system default.
func FindCCachePath ¶
func FindCCachePath() string
FindCCachePath locates the Kerberos credential cache file. Returns empty string if no usable file-based cache is found.
func GetCurrentMethod ¶ added in v0.18.0
GetCurrentMethod detects which 2FA method the current page is showing. Returns "otp", "webauthn", or "" if neither is detected.
func GetErrorMessage ¶
GetErrorMessage extracts the Keycloak error message from the page.
func GetErrorMessageFromHTML ¶
GetErrorMessageFromHTML parses HTML and extracts error message.
func GetPrincipalFromKlist ¶
GetPrincipalFromKlist parses the principal from klist output. Returns empty string if no principal found.
func HasTryAnotherWay ¶ added in v0.18.0
HasTryAnotherWay checks if the page has a "Try Another Way" option.
func IsMacOSAPICCache ¶
func IsMacOSAPICCache() bool
IsMacOSAPICCache returns true if we're on macOS and the credential cache is using the API: scheme (which is not accessible from pure Go).
func IsOTPRequired ¶
IsOTPRequired checks if the response requires OTP authentication.
func IsRefreshable ¶
IsRefreshable returns true if the OTP source supports refresh/retry.
func IsWebAuthnAvailable ¶
func IsWebAuthnAvailable() bool
IsWebAuthnAvailable returns true if WebAuthn support is compiled in.
func IsWebAuthnRequired ¶
IsWebAuthnRequired checks if the response requires WebAuthn/FIDO2 authentication.
func LoadKrb5Config ¶
LoadKrb5Config loads Kerberos configuration from the specified source. source can be:
- "" or "embedded": use the built-in CERN.CH configuration
- "system": use system krb5.conf (KRB5_CONFIG env var or /etc/krb5.conf)
- "/path/to/file": use a custom configuration file
func NewClientFromCCache ¶
NewClientFromCCache attempts to create a Kerberos client from the credential cache. Returns nil and an error if the cache is not found, invalid, or the TGT is expired.
func NormalizePrincipal ¶
NormalizePrincipal ensures the username has @CERN.CH suffix with correct case. Examples:
- "clange" -> "clange@CERN.CH"
- "clange@cern.ch" -> "clange@CERN.CH"
- "clange@CERN.CH" -> "clange@CERN.CH" (unchanged)
- "" -> "" (empty string returns empty)
func ParseGitLabOIDCForm ¶
ParseGitLabOIDCForm extracts the OIDC form data from a GitLab auto-submit page. GitLab puts the CSRF token in a meta tag, not in the input field.
func ParseKerberosLink ¶
ParseKerberosLink extracts the Kerberos login link from the SSO page.
func ParseSAMLForm ¶
ParseSAMLForm extracts the SAML action URL and form data from a response.
Types ¶
type AuthMethod ¶ added in v0.18.0
type AuthMethod struct {
ExecutionID string // The authenticationExecution value to submit
Type string // "otp" or "webauthn"
Label string // Human-readable label (e.g., "Authenticator Application")
}
AuthMethod represents an available 2FA authentication method.
type CacheInfo ¶
type CacheInfo struct {
Principal string // e.g., "clange@CERN.CH"
CacheName string // e.g., "API:EE3D6722-361C-4ACD-912F-DE88264999E2"
Expires time.Time // Expiry time of the TGT
IsDefault bool // True if this is the active cache (marked with *)
}
CacheInfo contains information about a Kerberos credential cache.
func FindCacheByUsername ¶
FindCacheByUsername finds a CERN.CH cache by username. The username can be provided with or without the @CERN.CH suffix. Returns error if no matching cache is found.
func ListCERNCaches ¶
ListCERNCaches returns all CERN.CH credential caches available on the system. This parses the output of `klist -l` and filters to only CERN.CH realm caches.
type KerberosClient ¶
type KerberosClient struct {
// contains filtered or unexported fields
}
KerberosClient handles Kerberos authentication.
func NewKerberosClient ¶
func NewKerberosClient(version string, krb5ConfigSource string, verifyCert bool) (*KerberosClient, error)
NewKerberosClient creates a new Kerberos client. It first attempts to use an existing credential cache (ccache), which works on Linux and macOS with file-based caches. If no valid ccache is found, it falls back to username/password authentication using KRB_USERNAME and KRB_PASSWORD environment variables. krb5ConfigSource can be "embedded" (default), "system", or a file path.
func NewKerberosClientWithUser ¶
func NewKerberosClientWithUser(version string, krb5ConfigSource string, krbUsername string, verifyCert bool) (*KerberosClient, error)
NewKerberosClientWithUser creates a new Kerberos client, optionally for a specific user. If krbUsername is provided, it will search for a matching CERN.CH credential cache and use that instead of the default cache. The username can be with or without the @CERN.CH suffix (e.g., "clange" or "clange@CERN.CH"). If no matching cache is found but KRB_PASSWORD is set, password-based auth is used. krb5ConfigSource can be "embedded" (default), "system", or a file path.
func (*KerberosClient) Close ¶
func (k *KerberosClient) Close()
Close cleans up the Kerberos client.
func (*KerberosClient) CollectCookies ¶
func (k *KerberosClient) CollectCookies(targetURL string, authHostname string, result *LoginResult) ([]*http.Cookie, error)
CollectCookies collects all cookies from the session with full attributes. This uses cookies intercepted from Set-Cookie headers during the authentication flow, which preserves the original Path and Domain attributes.
func (*KerberosClient) DoSPNEGO ¶
func (k *KerberosClient) DoSPNEGO(targetURL string) (*http.Response, error)
DoSPNEGO performs an HTTP GET request with SPNEGO authentication.
func (*KerberosClient) DoSPNEGORequest ¶
DoSPNEGORequest performs an HTTP request with SPNEGO authentication.
func (*KerberosClient) GetCollectedCookies ¶
func (k *KerberosClient) GetCollectedCookies() []*http.Cookie
GetCollectedCookies returns all cookies collected during the session with full attributes.
func (*KerberosClient) GetCookies ¶
func (k *KerberosClient) GetCookies(u *url.URL) []*http.Cookie
GetCookies returns all cookies from the jar for a given URL. It ensures the Domain field is populated if empty (Go's cookiejar doesn't populate it).
func (*KerberosClient) GetHTTPClient ¶
func (k *KerberosClient) GetHTTPClient() *http.Client
GetHTTPClient returns the HTTP client for non-SPNEGO requests.
func (*KerberosClient) LoginWithKerberos ¶
func (k *KerberosClient) LoginWithKerberos(loginPage string, authHostname string, verifyCert bool) (*LoginResult, error)
LoginWithKerberos performs the full Kerberos login flow.
func (*KerberosClient) SetOTPProvider ¶
func (k *KerberosClient) SetOTPProvider(provider *OTPProvider)
SetOTPProvider sets the OTP provider for 2FA authentication.
func (*KerberosClient) SetPreferredMethod ¶ added in v0.18.0
func (k *KerberosClient) SetPreferredMethod(method string)
SetPreferredMethod sets the preferred 2FA method. Valid values are "otp", "webauthn", or "" (use server default).
func (*KerberosClient) SetWebAuthnProvider ¶
func (k *KerberosClient) SetWebAuthnProvider(provider *WebAuthnProvider)
SetWebAuthnProvider sets the WebAuthn provider for FIDO2 2FA authentication.
func (*KerberosClient) TryLoginWithCookies ¶
func (k *KerberosClient) TryLoginWithCookies(targetURL string, authHostname string, cookies []*http.Cookie) (*LoginResult, error)
TryLoginWithCookies attempts to authenticate using existing auth.cern.ch cookies. This is useful for reusing existing SSO session cookies instead of performing full Kerberos authentication for each new CERN subdomain.
Example flow:
- User authenticates to account.web.cern.ch with Kerberos
- auth.cern.ch cookies are saved to cookies.txt
- Later, user wants to authenticate to gitlab.cern.ch
- TryLoginWithCookies reuses auth.cern.ch cookies
- Only falls back to Kerberos if cookies are expired/invalid
Returns success if cookies are valid (no redirect to auth hostname). Returns error if cookies are invalid/missing (caller should fall back to Kerberos).
type LoginError ¶
type LoginError struct {
Message string
}
LoginError wraps a login error with a message.
func (*LoginError) Error ¶
func (e *LoginError) Error() string
type LoginResult ¶
type LoginResult struct {
Cookies []*http.Cookie
RedirectURI string
Username string // The principal that was used for authentication
}
LoginResult contains the result of a Kerberos login.
type MethodSelectionPage ¶ added in v0.18.0
type MethodSelectionPage struct {
Action string // Form action URL
Methods []AuthMethod // Available authentication methods
}
MethodSelectionPage represents the page where users can choose their 2FA method.
func ParseMethodSelectionPage ¶ added in v0.18.0
func ParseMethodSelectionPage(r io.Reader) (*MethodSelectionPage, error)
ParseMethodSelectionPage extracts the available 2FA methods from the selection page. This page is shown after clicking "Try Another Way".
func (*MethodSelectionPage) FindMethod ¶ added in v0.18.0
func (p *MethodSelectionPage) FindMethod(methodType string) *AuthMethod
FindMethod finds a method by type in the selection page. Returns nil if the method is not available.
type OIDCConfig ¶
type OIDCConfig struct {
AuthHostname string
AuthRealm string
ClientID string
RedirectURI string
VerifyCert bool
Quiet bool
}
OIDCConfig holds configuration for OIDC flows.
type OTPForm ¶
type OTPForm struct {
Action string // Form action URL
HiddenFields map[string]string // Hidden input fields (CSRF tokens, etc.)
OTPField string // Name of the OTP input field
SubmitName string // Submit button name
SubmitValue string // Submit button value
}
OTPForm represents the structure of an OTP login form.
type OTPProvider ¶
type OTPProvider struct {
OTP string // Direct OTP value (from --otp flag or CERN_SSO_OTP)
OTPCommand string // Command to execute (from --otp-command flag or CERN_SSO_OTP_COMMAND)
MaxRetries int // Maximum retry attempts (default: 3)
}
OTPProvider handles OTP code retrieval from various sources. It checks sources in priority order: flag > command > env > prompt.
func (*OTPProvider) GetMaxRetries ¶
func (p *OTPProvider) GetMaxRetries() int
GetMaxRetries returns the configured max retries, defaulting to 3.
func (*OTPProvider) GetOTP ¶
func (p *OTPProvider) GetOTP(username string) (string, string, error)
GetOTP retrieves an OTP code using the configured sources. It tries sources in priority order:
- Direct OTP value (p.OTP)
- OTP command (p.OTPCommand)
- CERN_SSO_OTP environment variable
- CERN_SSO_OTP_COMMAND environment variable
- Interactive prompt (fallback)
Returns the OTP code and the source it was retrieved from.
func (*OTPProvider) RefreshOTP ¶
func (p *OTPProvider) RefreshOTP(username string, source string, attempt, maxRetries int) (string, error)
RefreshOTP gets a fresh OTP for retry attempts. For command sources, it waits for TOTP window rollover then re-executes. For interactive sources, it re-prompts the user. For static flag sources, it returns an error (cannot refresh).
type TokenResponse ¶
type TokenResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token,omitempty"`
Scope string `json:"scope,omitempty"`
}
TokenResponse represents an OIDC token response.
func DeviceAuthorizationFlow ¶
func DeviceAuthorizationFlow(cfg OIDCConfig) (*TokenResponse, error)
DeviceAuthorizationFlow performs the OAuth2 Device Authorization Grant flow.
func TokenExchange ¶
func TokenExchange(cfg OIDCConfig, subjectToken, audience string) (*TokenResponse, error)
TokenExchange performs a token exchange.
type TryAnotherWayForm ¶ added in v0.18.0
type TryAnotherWayForm struct {
Action string // Form action URL
}
TryAnotherWayForm represents the form to switch 2FA methods.
func ParseTryAnotherWayForm ¶ added in v0.18.0
func ParseTryAnotherWayForm(r io.Reader) (*TryAnotherWayForm, error)
ParseTryAnotherWayForm extracts the "Try Another Way" form from a 2FA page.
type WebAuthnForm ¶
type WebAuthnForm struct {
Action string // Form action URL
Challenge string // Base64URL-encoded challenge
RPID string // Relying Party ID
CredentialIDs []string // Allowed credential IDs (base64url encoded)
UserHandle string // User handle (base64url encoded)
HiddenFields map[string]string // Other hidden input fields
}
WebAuthnForm represents the structure of a Keycloak WebAuthn form.
func ParseWebAuthnForm ¶
func ParseWebAuthnForm(r io.Reader) (*WebAuthnForm, error)
ParseWebAuthnForm extracts the WebAuthn form details from the CERN 2FA page. Keycloak's WebAuthn page structure: - <div id="kc-form-webauthn"> is a wrapper div - <form id="webauth" action="..."> is the actual form inside - Challenge and rpId are in JavaScript, not form fields
type WebAuthnProvider ¶
type WebAuthnProvider struct {
DevicePath string // Optional: specific device path, empty = auto-detect
PIN string // Device PIN if required
Timeout time.Duration // Timeout for device interaction
UseBrowser bool // Fall back to browser-based flow
}
WebAuthnProvider handles FIDO2 authentication with security keys.
func (*WebAuthnProvider) Authenticate ¶
func (p *WebAuthnProvider) Authenticate(form *WebAuthnForm) (*WebAuthnResult, error)
Authenticate performs FIDO2 assertion with the connected device. Returns the assertion data formatted for Keycloak submission.
func (*WebAuthnProvider) GetPIN ¶
func (p *WebAuthnProvider) GetPIN() (string, error)
GetPIN retrieves the PIN using the configured sources. Priority: struct field > environment variable > interactive prompt.
func (*WebAuthnProvider) GetTimeout ¶
func (p *WebAuthnProvider) GetTimeout() time.Duration
GetTimeout returns the configured timeout, defaulting to 30 seconds.
type WebAuthnResult ¶
type WebAuthnResult struct {
ClientDataJSON string // base64url-encoded clientDataJSON
AuthenticatorData string // base64url-encoded authenticatorData
Signature string // base64url-encoded signature
CredentialID string // base64url-encoded credential ID used
UserHandle string // base64url-encoded user handle (if present)
}
WebAuthnResult contains the response data to submit to Keycloak.