Documentation
¶
Overview ¶
Package auth provides authentication utilities for CERN SSO.
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 GetSPALoginPage(client *http.Client, spaInfo *SPAInfo, authHostname string) (string, []byte, 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 AuthConfig
- type AuthMethod
- type CacheInfo
- type FIDO2DeviceInfo
- type HarborSystemInfo
- type KerberosClient
- func NewKerberosClient(version string, krb5ConfigSource string, verifyCert bool) (*KerberosClient, error)
- func NewKerberosClientWithConfig(version string, krb5ConfigSource string, krbUsername string, verifyCert bool, ...) (*KerberosClient, error)
- func NewKerberosClientWithUser(version string, krb5ConfigSource string, krbUsername string, verifyCert bool) (*KerberosClient, error)
- 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) ExportCCache(path string) 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 SPAInfo
- 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 ( SPATypeUnknown = "" SPATypeHarbor = "harbor" SPATypeOpenShift = "openshift" )
SPAType constants for known SPA applications
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 GetSPALoginPage ¶ added in v0.27.0
func GetSPALoginPage(client *http.Client, spaInfo *SPAInfo, authHostname string) (string, []byte, error)
GetSPALoginPage navigates through the SPA login flow to reach the SSO page. Returns the login page URL and its body content.
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 AuthConfig ¶ added in v0.24.0
type AuthConfig struct {
KeytabPath string // Explicit keytab path from --keytab flag
ForcePassword bool // --use-password flag
ForceKeytab bool // --use-keytab flag (or implied by --keytab)
ForceCCache bool // --use-ccache flag
Quiet bool // --quiet flag (suppress non-error output)
}
AuthConfig holds authentication method configuration.
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 FIDO2DeviceInfo ¶ added in v0.25.0
type FIDO2DeviceInfo struct {
Index int // 0-based index for selection
Path string // Device path (e.g., /dev/hidraw0)
Product string // Product name (e.g., "YubiKey 5 NFC")
}
FIDO2DeviceInfo contains information about an available FIDO2 device.
func ListFIDO2Devices ¶ added in v0.25.0
func ListFIDO2Devices() ([]FIDO2DeviceInfo, error)
ListFIDO2Devices returns a list of available FIDO2 devices. Returns an empty slice if no devices are found or if enumeration fails.
type HarborSystemInfo ¶ added in v0.27.0
type HarborSystemInfo struct {
AuthMode string `json:"auth_mode"`
OIDCProviderName string `json:"oidc_provider_name"`
HarborVersion string `json:"harbor_version"`
}
HarborSystemInfo represents the Harbor systeminfo API response
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 with automatic authentication. This is a convenience wrapper that uses automatic authentication method selection. krb5ConfigSource can be "embedded" (default), "system", or a file path.
func NewKerberosClientWithConfig ¶ added in v0.24.0
func NewKerberosClientWithConfig(version string, krb5ConfigSource string, krbUsername string, verifyCert bool, authConfig AuthConfig) (*KerberosClient, error)
NewKerberosClientWithConfig creates a new Kerberos client with full configuration. This function supports explicit authentication method selection via AuthConfig, and automatic method selection when no explicit method is specified.
Authentication priority (when no explicit method is specified):
- Password (if KRB5_USERNAME and KRB5_PASSWORD are set)
- Keytab (if KRB5_KTNAME is set)
- Credential cache (ccache)
- Default keytab locations (~/.keytab, /etc/krb5.keytab)
func NewKerberosClientWithUser ¶
func NewKerberosClientWithUser(version string, krb5ConfigSource string, krbUsername string, verifyCert bool) (*KerberosClient, error)
NewKerberosClientWithUser creates a new Kerberos client for a specific user. This is a convenience wrapper that uses automatic authentication method selection. 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) ExportCCache ¶ added in v0.26.0
func (k *KerberosClient) ExportCCache(path string) error
ExportCCache writes the internal Kerberos credentials to a ccache file.
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 SPAInfo ¶ added in v0.27.0
type SPAInfo struct {
Type string // SPATypeHarbor, SPATypeOpenShift, etc.
LoginURL string // Direct login URL that triggers OIDC flow
ClientID string // OIDC client ID (if extractable)
BaseURL string // Base URL of the target site
}
SPAInfo contains detected SPA configuration
func DetectHarbor ¶ added in v0.27.0
DetectHarbor checks for Harbor registry indicators by probing the systeminfo API.
func DetectOpenShift ¶ added in v0.27.0
DetectOpenShift checks for OpenShift/OKD indicators in the HTML response.
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
DeviceIndex int // Optional: device index (0-based), -1 = auto-detect first device
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.