diff --git a/handlers.go b/handlers.go index a1784937dabf51d31e338ddf8e206e8fdc8cd06c..df5e37cbeb2aeb252b7a23949bbc2c58a1bf841e 100644 --- a/handlers.go +++ b/handlers.go @@ -48,7 +48,7 @@ const ( // // loggingHandler is a custom http logger // -func (r *KeycloakProxy) loggingHandler() gin.HandlerFunc { +func (r *keycloakProxy) loggingHandler() gin.HandlerFunc { return func(cx *gin.Context) { start := time.Now() cx.Next() @@ -68,7 +68,7 @@ func (r *KeycloakProxy) loggingHandler() gin.HandlerFunc { // // securityHandler performs numerous security checks on the request // -func (r *KeycloakProxy) securityHandler() gin.HandlerFunc { +func (r *keycloakProxy) securityHandler() gin.HandlerFunc { // step: create the security options secure := secure.New(secure.Options{ AllowedHosts: r.config.Hostnames, @@ -94,7 +94,7 @@ func (r *KeycloakProxy) securityHandler() gin.HandlerFunc { // // entryPointHandler checks to see if the request requires authentication // -func (r *KeycloakProxy) entryPointHandler() gin.HandlerFunc { +func (r *keycloakProxy) entryPointHandler() gin.HandlerFunc { return func(cx *gin.Context) { if strings.HasPrefix(cx.Request.URL.Path, oauthURL) { cx.Next() @@ -144,7 +144,7 @@ func (r *KeycloakProxy) entryPointHandler() gin.HandlerFunc { // - else we validate the access token against the keypair via openid client // - if everything is cool, move on, else thrown a redirect or forbidden // -func (r *KeycloakProxy) authenticationHandler() gin.HandlerFunc { +func (r *keycloakProxy) authenticationHandler() gin.HandlerFunc { return func(cx *gin.Context) { var session jose.JWT @@ -265,7 +265,7 @@ func (r *KeycloakProxy) authenticationHandler() gin.HandlerFunc { // - if er have any claim requirements validate the claims are the same // - if everything is ok, we permit the request to pass through // -func (r *KeycloakProxy) admissionHandler() gin.HandlerFunc { +func (r *keycloakProxy) admissionHandler() gin.HandlerFunc { // step: compile the regex's for the claims claimMatches := make(map[string]*regexp.Regexp, 0) for k, v := range r.config.ClaimsMatch { @@ -365,7 +365,7 @@ func (r *KeycloakProxy) admissionHandler() gin.HandlerFunc { // // proxyHandler is responsible to proxy the requests on to the upstream endpoint // -func (r *KeycloakProxy) proxyHandler(cx *gin.Context) { +func (r *keycloakProxy) proxyHandler(cx *gin.Context) { // step: double check, if enforce is true and no user context it's a internal error if _, found := cx.Get(cxEnforce); found { if _, found := cx.Get(userContextName); !found { @@ -416,7 +416,7 @@ func (r *KeycloakProxy) proxyHandler(cx *gin.Context) { // // oauthAuthorizationHandler is responsible for performing the redirection to keycloak service // -func (r *KeycloakProxy) oauthAuthorizationHandler(cx *gin.Context) { +func (r *keycloakProxy) oauthAuthorizationHandler(cx *gin.Context) { // step: is token verification switched on? if r.config.SkipTokenVerification { r.accessForbidden(cx) @@ -466,7 +466,7 @@ func (r *KeycloakProxy) oauthAuthorizationHandler(cx *gin.Context) { // // oauthCallbackHandler is responsible for handling the response from keycloak // -func (r *KeycloakProxy) oauthCallbackHandler(cx *gin.Context) { +func (r *keycloakProxy) oauthCallbackHandler(cx *gin.Context) { // step: is token verification switched on? if r.config.SkipTokenVerification { r.accessForbidden(cx) @@ -584,7 +584,7 @@ func (r *KeycloakProxy) oauthCallbackHandler(cx *gin.Context) { // // expirationHandler checks if the token has expired // -func (r *KeycloakProxy) expirationHandler(cx *gin.Context) { +func (r *keycloakProxy) expirationHandler(cx *gin.Context) { // step: get the access token from the request token, err := r.getSession(cx) if err != nil { @@ -620,7 +620,7 @@ func (r *KeycloakProxy) expirationHandler(cx *gin.Context) { // // tokenHandle display access token to screen // -func (r *KeycloakProxy) tokenHandler(cx *gin.Context) { +func (r *keycloakProxy) tokenHandler(cx *gin.Context) { // step: extract the access token from the request token, err := r.getSession(cx) if err != nil { @@ -640,6 +640,6 @@ func (r *KeycloakProxy) tokenHandler(cx *gin.Context) { // // healthHandler is a health check handler for the service // -func (r *KeycloakProxy) healthHandler(cx *gin.Context) { +func (r *keycloakProxy) healthHandler(cx *gin.Context) { cx.String(http.StatusOK, "OK") } diff --git a/oauth.go b/oauth.go index 2dc8e89ff5eeb273a3ae40b601d23f20059a4c0a..74920cc2ae314adf35e158e1aa4ae7a4148fae92 100644 --- a/oauth.go +++ b/oauth.go @@ -25,7 +25,7 @@ import ( ) // refreshAccessToken attempts to refresh the access token, returning the parsed token and the time it expires or a error -func (r *KeycloakProxy) refreshAccessToken(refreshToken string) (jose.JWT, time.Time, error) { +func (r *keycloakProxy) refreshAccessToken(refreshToken string) (jose.JWT, time.Time, error) { // step: refresh the access token response, err := r.getToken(oauth2.GrantTypeRefreshToken, refreshToken) if err != nil { @@ -45,7 +45,7 @@ func (r *KeycloakProxy) refreshAccessToken(refreshToken string) (jose.JWT, time. } // parseToken retrieve the user identity from the token -func (r *KeycloakProxy) parseToken(accessToken string) (jose.JWT, *oidc.Identity, error) { +func (r *keycloakProxy) parseToken(accessToken string) (jose.JWT, *oidc.Identity, error) { // step: parse and return the token token, err := jose.ParseJWT(accessToken) if err != nil { @@ -68,7 +68,7 @@ func (r *KeycloakProxy) parseToken(accessToken string) (jose.JWT, *oidc.Identity } // verifyToken verify that the token in the user context is valid -func (r *KeycloakProxy) verifyToken(token jose.JWT) error { +func (r *keycloakProxy) verifyToken(token jose.JWT) error { // step: verify the token is whom they say they are if err := r.openIDClient.VerifyJWT(token); err != nil { if strings.Contains(err.Error(), "token is expired") { @@ -82,7 +82,7 @@ func (r *KeycloakProxy) verifyToken(token jose.JWT) error { } // getToken retrieves a code from the provider, extracts and verified the token -func (r *KeycloakProxy) getToken(grantType, code string) (oauth2.TokenResponse, error) { +func (r *keycloakProxy) getToken(grantType, code string) (oauth2.TokenResponse, error) { var response oauth2.TokenResponse // step: retrieve the client diff --git a/server.go b/server.go index f5860be38a1b9b0323fce550030dbec7082a8b3d..b2b0485aaf3062d8cefefca8b266b04dd55db38e 100644 --- a/server.go +++ b/server.go @@ -35,8 +35,8 @@ import ( "github.com/gin-gonic/gin" ) -// KeycloakProxy is the server component -type KeycloakProxy struct { +// keycloakProxy is the server component +type keycloakProxy struct { config *Config // the gin service router *gin.Engine @@ -60,7 +60,7 @@ func init() { } // newKeycloakProxy create's a new keycloak proxy from configuration -func newKeycloakProxy(cfg *Config) (*KeycloakProxy, error) { +func newKeycloakProxy(cfg *Config) (*keycloakProxy, error) { // step: set the logging level if cfg.LogJSONFormat { log.SetFormatter(&log.JSONFormatter{}) @@ -78,7 +78,7 @@ func newKeycloakProxy(cfg *Config) (*KeycloakProxy, error) { } // step: create a proxy service - service := &KeycloakProxy{ + service := &keycloakProxy{ config: cfg, upstreamURL: upstreamURL, } @@ -122,7 +122,7 @@ func newKeycloakProxy(cfg *Config) (*KeycloakProxy, error) { } // initializeRouter sets up the gin routing -func (r KeycloakProxy) initializeRouter() { +func (r keycloakProxy) initializeRouter() { r.router.Use(gin.Recovery()) // step: are we logging the traffic? if r.config.LogRequests { @@ -145,7 +145,7 @@ func (r KeycloakProxy) initializeRouter() { } // initializeTemplates loads the custom template -func (r *KeycloakProxy) initializeTemplates() { +func (r *keycloakProxy) initializeTemplates() { var list []string if r.config.SignInPage != "" { @@ -164,7 +164,7 @@ func (r *KeycloakProxy) initializeTemplates() { } // Run starts the proxy service -func (r *KeycloakProxy) Run() error { +func (r *keycloakProxy) Run() error { tlsConfig := &tls.Config{} // step: are we doing mutual tls? @@ -205,7 +205,7 @@ func (r *KeycloakProxy) Run() error { } // redirectToURL redirects the user and aborts the context -func (r KeycloakProxy) redirectToURL(url string, cx *gin.Context) { +func (r keycloakProxy) redirectToURL(url string, cx *gin.Context) { // step: add the cors headers r.injectCORSHeaders(cx) @@ -214,7 +214,7 @@ func (r KeycloakProxy) redirectToURL(url string, cx *gin.Context) { } // accessForbidden redirects the user to the forbidden page -func (r KeycloakProxy) accessForbidden(cx *gin.Context) { +func (r keycloakProxy) accessForbidden(cx *gin.Context) { // step: do we have a custom forbidden page if r.config.hasForbiddenPage() { cx.HTML(http.StatusForbidden, path.Base(r.config.ForbiddenPage), r.config.TagData) @@ -226,7 +226,7 @@ func (r KeycloakProxy) accessForbidden(cx *gin.Context) { } // redirectToAuthorization redirects the user to authorization handler -func (r KeycloakProxy) redirectToAuthorization(cx *gin.Context) { +func (r keycloakProxy) redirectToAuthorization(cx *gin.Context) { // step: are we handling redirects? if r.config.NoRedirects { cx.AbortWithStatus(http.StatusUnauthorized) @@ -247,7 +247,7 @@ func (r KeycloakProxy) redirectToAuthorization(cx *gin.Context) { } // injectCORSHeaders adds the cors access controls to the oauth responses -func (r *KeycloakProxy) injectCORSHeaders(cx *gin.Context) { +func (r *keycloakProxy) injectCORSHeaders(cx *gin.Context) { c := r.config.CORS if len(c.Origins) > 0 { cx.Writer.Header().Set("Access-Control-Allow-Origin", strings.Join(c.Origins, ",")) @@ -269,7 +269,7 @@ func (r *KeycloakProxy) injectCORSHeaders(cx *gin.Context) { } } -func (r *KeycloakProxy) addAuthenticationHeader(cx *gin.Context, errorCode, errorMessage string) { +func (r *keycloakProxy) addAuthenticationHeader(cx *gin.Context, errorCode, errorMessage string) { // step: inject the error message header := "Bearer realm=\"secure\"" if errorCode != "" { @@ -284,7 +284,7 @@ func (r *KeycloakProxy) addAuthenticationHeader(cx *gin.Context, errorCode, erro } // tryUpdateConnection attempt to upgrade the connection to a http pdy stream -func (r *KeycloakProxy) tryUpdateConnection(cx *gin.Context) error { +func (r *keycloakProxy) tryUpdateConnection(cx *gin.Context) error { // step: dial the endpoint tlsConn, err := tryDialEndpoint(r.upstreamURL) if err != nil { @@ -315,7 +315,7 @@ func (r *KeycloakProxy) tryUpdateConnection(cx *gin.Context) error { } // initializeReverseProxy create a reverse http proxy from the upstream -func (r *KeycloakProxy) initializeReverseProxy(upstream *url.URL) (reverseProxy, error) { +func (r *keycloakProxy) initializeReverseProxy(upstream *url.URL) (reverseProxy, error) { proxy := httputil.NewSingleHostReverseProxy(upstream) // step: we don't care about the cert verification here diff --git a/server_test.go b/server_test.go index 8cbfb90d38881232c026eee6b0d2332ad6c98088..b0ff3c57383375c137b82265e24020bea829a894 100644 --- a/server_test.go +++ b/server_test.go @@ -44,7 +44,7 @@ const ( fakeTestRole = "role:test" ) -func newFakeKeycloakProxyWithResources(t *testing.T, resources []*Resource) *KeycloakProxy { +func newFakeKeycloakProxyWithResources(t *testing.T, resources []*Resource) *keycloakProxy { kc := newFakeKeycloakProxy(t) kc.config.Resources = resources return kc @@ -97,10 +97,10 @@ func newFakeKeycloakConfig(t *testing.T) *Config { } } -func newFakeKeycloakProxy(t *testing.T) *KeycloakProxy { +func newFakeKeycloakProxy(t *testing.T) *keycloakProxy { log.SetOutput(ioutil.Discard) - kc := &KeycloakProxy{ + kc := &keycloakProxy{ config: newFakeKeycloakConfig(t), proxy: new(fakeReverseProxy), } diff --git a/session.go b/session.go index a76bc1b2f0e0c3e4a01b48b55e8845d1a5f1d92e..4cbcf478f26255c486c41e6b061dbc1f36a6af6a 100644 --- a/session.go +++ b/session.go @@ -46,7 +46,7 @@ type sessionState struct { // refreshUserSessionToken is responsible for retrieving the session state cookie and attempting to refresh the access // token for the user -func (r *KeycloakProxy) refreshUserSessionToken(cx *gin.Context) (jose.JWT, error) { +func (r *keycloakProxy) refreshUserSessionToken(cx *gin.Context) (jose.JWT, error) { // step: grab the session state cooke state, err := r.getSessionState(cx) if err != nil { @@ -86,7 +86,7 @@ func (r *KeycloakProxy) refreshUserSessionToken(cx *gin.Context) (jose.JWT, erro // getSessionToken retrieves the authentication cookie from the request and parse's into a JWT token // The token can come either a session cookie or a Bearer header -func (r *KeycloakProxy) getSessionToken(cx *gin.Context) (jose.JWT, bool, error) { +func (r *keycloakProxy) getSessionToken(cx *gin.Context) (jose.JWT, bool, error) { var session string isBearer := false @@ -113,14 +113,14 @@ func (r *KeycloakProxy) getSessionToken(cx *gin.Context) (jose.JWT, bool, error) } // getSession is a helper methods for those whom dont care if it's a bearer token -func (r *KeycloakProxy) getSession(cx *gin.Context) (jose.JWT, error) { +func (r *keycloakProxy) getSession(cx *gin.Context) (jose.JWT, error) { token, _, err := r.getSessionToken(cx) return token, err } // getSessionState retrieves the session state from the request -func (r *KeycloakProxy) getSessionState(cx *gin.Context) (*sessionState, error) { +func (r *keycloakProxy) getSessionState(cx *gin.Context) (*sessionState, error) { // step: find the session data cookie cookie := findCookie(sessionStateCookieName, cx.Request.Cookies()) if cookie == nil { @@ -131,7 +131,7 @@ func (r *KeycloakProxy) getSessionState(cx *gin.Context) (*sessionState, error) } // getUserContext parse the jwt token and extracts the various elements is order to construct -func (r *KeycloakProxy) getUserContext(token jose.JWT) (*userContext, error) { +func (r *keycloakProxy) getUserContext(token jose.JWT) (*userContext, error) { // step: decode the claims from the tokens claims, err := token.Claims() if err != nil { @@ -194,14 +194,14 @@ func (r *KeycloakProxy) getUserContext(token jose.JWT) (*userContext, error) { } // createSession creates a session cookie with the access token -func (r *KeycloakProxy) createSession(token jose.JWT, expires time.Time, cx *gin.Context) error { +func (r *keycloakProxy) createSession(token jose.JWT, expires time.Time, cx *gin.Context) error { http.SetCookie(cx.Writer, createSessionCookie(token.Encode(), cx.Request.Host, expires.Add(time.Duration(5)*time.Minute))) return nil } // createSessionState creates a session state cookie, used to hold the refresh cookie and the expiration time -func (r *KeycloakProxy) createSessionState(state *sessionState, cx *gin.Context) error { +func (r *keycloakProxy) createSessionState(state *sessionState, cx *gin.Context) error { // step: we need to encode the state encoded, err := r.encryptStateSession(state) if err != nil { @@ -214,7 +214,7 @@ func (r *KeycloakProxy) createSessionState(state *sessionState, cx *gin.Context) } // encryptStateSession encodes the session state information into a value for a cookie to consume -func (r *KeycloakProxy) encryptStateSession(session *sessionState) (string, error) { +func (r *keycloakProxy) encryptStateSession(session *sessionState) (string, error) { // step: encode the session into a string encoded := fmt.Sprintf("%d|%s", session.expireOn.Unix(), session.refreshToken) @@ -228,7 +228,7 @@ func (r *KeycloakProxy) encryptStateSession(session *sessionState) (string, erro } // decryptStateSession decodes the session state cookie value -func (r *KeycloakProxy) decryptStateSession(state string) (*sessionState, error) { +func (r *keycloakProxy) decryptStateSession(state string) (*sessionState, error) { // step: decode the base64 encrypted cookie cipherText, err := base64.StdEncoding.DecodeString(state) if err != nil {