Skip to content

Commit

Permalink
Merge pull request #186 from jonstacks/issue-136
Browse files Browse the repository at this point in the history
Add SAML Route Module
  • Loading branch information
jonstacks authored Mar 17, 2023
2 parents a2095d6 + bc4e461 commit 421d583
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 0 deletions.
3 changes: 3 additions & 0 deletions api/v1alpha1/httpsedge_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ type HTTPSEdgeRouteSpec struct {
// OIDC is the OpenID Connect configuration to apply to this route
OIDC *EndpointOIDC `json:"oidc,omitempty"`

// SAML is the SAML configuration to apply to this route
SAML *EndpointSAML `json:"saml,omitempty"`

// WebhookVerification is webhook verification configuration to apply to this route
WebhookVerification *EndpointWebhookVerification `json:"webhookVerification,omitempty"`
}
Expand Down
38 changes: 38 additions & 0 deletions api/v1alpha1/ngrok_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,41 @@ type EndpointOIDC struct {
// The set of scopes to request from the OIDC identity provider.
Scopes []string `json:"scopes,omitempty"`
}

type EndpointSAML struct {
// Do not enforce authentication on HTTP OPTIONS requests. necessary if you are
// supporting CORS.
OptionsPassthrough bool `json:"optionsPassthrough,omitempty"`
// the prefix of the session cookie that ngrok sets on the http client to cache
// authentication. default is 'ngrok.'
CookiePrefix string `json:"cookiePrefix,omitempty"`
// Duration of inactivity after which if the user has not accessed
// the endpoint, their session will time out and they will be forced to
// reauthenticate.
//+kubebuilder:validation:Format=duration
InactivityTimeout v1.Duration `json:"inactivityTimeout,omitempty"`
// The maximum duration of an authenticated session.
// After this period is exceeded, a user must reauthenticate.
//+kubebuilder:validation:Format=duration
MaximumDuration v1.Duration `json:"maximumDuration,omitempty"`
// The full XML IdP EntityDescriptor. Your IdP may provide this to you as a a file
// to download or as a URL.
IdPMetadata string `json:"idpMetadata,omitempty"`
// If true, indicates that whenever we redirect a user to the IdP for
// authentication that the IdP must prompt the user for authentication credentials
// even if the user already has a valid session with the IdP.
ForceAuthn bool `json:"forceAuthn,omitempty"`
// If true, the IdP may initiate a login directly (e.g. the user does not need to
// visit the endpoint first and then be redirected). The IdP should set the
// RelayState parameter to the target URL of the resource they want the user to be
// redirected to after the SAML login assertion has been processed.
AllowIdPInitiated *bool `json:"allowIdpInitiated,omitempty"`
// If present, only users who are a member of one of the listed groups may access
// the target endpoint.
AuthorizedGroups []string `json:"authorizedGroups,omitempty"`
// Defines the name identifier format the SP expects the IdP to use in its
// assertions to identify subjects. If unspecified, a default value of
// urn:oasis:names:tc:SAML:2.0:nameid-format:persistent will be used. A subset of
// the allowed values enumerated by the SAML specification are supported.
NameIDFormat string `json:"nameidFormat,omitempty"`
}
5 changes: 5 additions & 0 deletions api/v1alpha1/ngrokmoduleset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ type NgrokModuleSetModules struct {
IPRestriction *EndpointIPPolicy `json:"ipRestriction,omitempty"`
// OIDC configuration for this module set
OIDC *EndpointOIDC `json:"oidc,omitempty"`
// SAML configuration for this module set
SAML *EndpointSAML `json:"saml,omitempty"`
// TLSTermination configuration for this module set
TLSTermination *EndpointTLSTerminationAtEdge `json:"tlsTermination,omitempty"`
// WebhookVerification configuration for this module set
Expand Down Expand Up @@ -79,6 +81,9 @@ func (ms *NgrokModuleSet) Merge(o *NgrokModuleSet) {
if omod.OIDC != nil {
msmod.OIDC = omod.OIDC
}
if omod.SAML != nil {
msmod.SAML = omod.SAML
}
if omod.TLSTermination != nil {
msmod.TLSTermination = omod.TLSTermination
}
Expand Down
37 changes: 37 additions & 0 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions internal/controllers/httpsedge_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,7 @@ func (u *edgeRouteModuleUpdater) updateModulesForRoute(ctx context.Context, rout
u.setEdgeRouteRequestHeaders,
u.setEdgeRouteResponseHeaders,
u.setEdgeRouteOIDC,
u.setEdgeRouteSAML,
u.setEdgeRouteWebhookVerification,
}

Expand Down Expand Up @@ -688,6 +689,44 @@ func (u *edgeRouteModuleUpdater) setEdgeRouteOIDC(ctx context.Context, route *ng
return err
}

func (u *edgeRouteModuleUpdater) setEdgeRouteSAML(ctx context.Context, route *ngrok.HTTPSEdgeRoute, routeSpec *ingressv1alpha1.HTTPSEdgeRouteSpec) error {
saml := routeSpec.SAML
client := u.clientset.SAML()

if saml == nil {
if route.SAML == nil {
u.log.Info("SAML matches desired state, skipping update")
return nil
}

return client.Delete(ctx, u.edgeRouteItem(route))
}

module := ngrok.EndpointSAMLMutate{
OptionsPassthrough: saml.OptionsPassthrough,
CookiePrefix: saml.CookiePrefix,
InactivityTimeout: uint32(saml.InactivityTimeout.Seconds()),
MaximumDuration: uint32(saml.MaximumDuration.Seconds()),
IdPMetadata: saml.IdPMetadata,
ForceAuthn: saml.ForceAuthn,
AllowIdPInitiated: saml.AllowIdPInitiated,
AuthorizedGroups: saml.AuthorizedGroups,
NameIDFormat: saml.NameIDFormat,
}

if reflect.DeepEqual(&module, route.SAML) {
u.log.Info("SAML matches desired state, skipping update")
return nil
}

_, err := client.Replace(ctx, &ngrok.EdgeRouteSAMLReplace{
EdgeID: route.EdgeID,
ID: route.ID,
Module: module,
})
return err
}

func (u *edgeRouteModuleUpdater) setEdgeRouteWebhookVerification(ctx context.Context, route *ngrok.HTTPSEdgeRoute, routeSpec *ingressv1alpha1.HTTPSEdgeRouteSpec) error {
webhookVerification := routeSpec.WebhookVerification

Expand Down
1 change: 1 addition & 0 deletions internal/store/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ func (d *Driver) calculateHTTPSEdges() []ingressv1alpha1.HTTPSEdge {
IPRestriction: modSet.Modules.IPRestriction,
Headers: modSet.Modules.Headers,
OIDC: modSet.Modules.OIDC,
SAML: modSet.Modules.SAML,
WebhookVerification: modSet.Modules.WebhookVerification,
}
route.Metadata = d.customMetadata
Expand Down

0 comments on commit 421d583

Please sign in to comment.