-
Notifications
You must be signed in to change notification settings - Fork 117
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
BED-4851 Create OIDC Provider Endpoint (#881)
* BED-4851 Create OIDC Provider Endpoint & migration
- Loading branch information
Showing
13 changed files
with
505 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright 2024 Specter Ops, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package auth | ||
|
||
import ( | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/specterops/bloodhound/src/utils/validation" | ||
|
||
"github.com/specterops/bloodhound/src/api" | ||
) | ||
|
||
// CreateOIDCProviderRequest represents the body of the CreateOIDCProvider endpoint | ||
type CreateOIDCProviderRequest struct { | ||
Name string `json:"name" validate:"required"` | ||
Issuer string `json:"issuer" validate:"url"` | ||
ClientID string `json:"client_id" validate:"required"` | ||
} | ||
|
||
// CreateOIDCProvider creates an OIDC provider entry given a valid request | ||
func (s ManagementResource) CreateOIDCProvider(response http.ResponseWriter, request *http.Request) { | ||
var ( | ||
createRequest = CreateOIDCProviderRequest{} | ||
) | ||
|
||
if err := api.ReadJSONRequestPayloadLimited(&createRequest, request); err != nil { | ||
api.WriteErrorResponse(request.Context(), api.BuildErrorResponse(http.StatusBadRequest, err.Error(), request), response) | ||
} else if validated := validation.Validate(createRequest); validated != nil { | ||
api.WriteErrorResponse(request.Context(), api.BuildErrorResponse(http.StatusBadRequest, validated.Error(), request), response) | ||
} else if strings.Contains(createRequest.Name, " ") { | ||
api.WriteErrorResponse(request.Context(), api.BuildErrorResponse(http.StatusBadRequest, "invalid name formatting, ensure there are no spaces in the provided name", request), response) | ||
} else { | ||
var ( | ||
formattedName = strings.ToLower(createRequest.Name) | ||
) | ||
|
||
if provider, err := s.db.CreateOIDCProvider(request.Context(), formattedName, createRequest.Issuer, createRequest.ClientID); err != nil { | ||
api.HandleDatabaseError(request, response, err) | ||
} else { | ||
api.WriteBasicResponse(request.Context(), provider, http.StatusCreated, response) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
// Copyright 2024 Specter Ops, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package auth_test | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/specterops/bloodhound/src/model" | ||
|
||
"github.com/specterops/bloodhound/src/api/v2/auth" | ||
|
||
"github.com/specterops/bloodhound/src/api/v2/apitest" | ||
"github.com/specterops/bloodhound/src/utils/test" | ||
|
||
"testing" | ||
|
||
"go.uber.org/mock/gomock" | ||
) | ||
|
||
func TestManagementResource_CreateOIDCProvider(t *testing.T) { | ||
const ( | ||
url = "/api/v2/sso/providers/oidc" | ||
) | ||
var ( | ||
mockCtrl = gomock.NewController(t) | ||
resources, mockDB = apitest.NewAuthManagementResource(mockCtrl) | ||
) | ||
defer mockCtrl.Finish() | ||
|
||
t.Run("successfully create a new OIDCProvider", func(t *testing.T) { | ||
mockDB.EXPECT().CreateOIDCProvider(gomock.Any(), "test", "https://localhost/auth", "bloodhound").Return(model.OIDCProvider{ | ||
Name: "", | ||
ClientID: "", | ||
Issuer: "", | ||
}, nil) | ||
|
||
test.Request(t). | ||
WithMethod(http.MethodPost). | ||
WithURL(url). | ||
WithBody(auth.CreateOIDCProviderRequest{ | ||
Name: "test", | ||
Issuer: "https://localhost/auth", | ||
|
||
ClientID: "bloodhound", | ||
}). | ||
OnHandlerFunc(resources.CreateOIDCProvider). | ||
Require(). | ||
ResponseStatusCode(http.StatusCreated) | ||
}) | ||
|
||
t.Run("error parsing body request", func(t *testing.T) { | ||
test.Request(t). | ||
WithMethod(http.MethodPost). | ||
WithURL(url). | ||
WithBody(""). | ||
OnHandlerFunc(resources.CreateOIDCProvider). | ||
Require(). | ||
ResponseStatusCode(http.StatusBadRequest) | ||
}) | ||
|
||
t.Run("error validating request field", func(t *testing.T) { | ||
test.Request(t). | ||
WithMethod(http.MethodPost). | ||
WithURL(url). | ||
WithBody(auth.CreateOIDCProviderRequest{ | ||
Name: "test", | ||
Issuer: "", | ||
}). | ||
OnHandlerFunc(resources.CreateOIDCProvider). | ||
Require(). | ||
ResponseStatusCode(http.StatusBadRequest) | ||
}) | ||
|
||
t.Run("error invalid Issuer", func(t *testing.T) { | ||
request := auth.CreateOIDCProviderRequest{ | ||
Issuer: "12345:bloodhound", | ||
} | ||
test.Request(t). | ||
WithMethod(http.MethodPost). | ||
WithURL(url). | ||
WithBody(request). | ||
OnHandlerFunc(resources.CreateOIDCProvider). | ||
Require(). | ||
ResponseStatusCode(http.StatusBadRequest) | ||
}) | ||
|
||
t.Run("error creating oidc provider db entry", func(t *testing.T) { | ||
mockDB.EXPECT().CreateOIDCProvider(gomock.Any(), "test", "https://localhost/auth", "bloodhound").Return(model.OIDCProvider{}, fmt.Errorf("error")) | ||
|
||
test.Request(t). | ||
WithMethod(http.MethodPost). | ||
WithURL(url). | ||
WithBody(auth.CreateOIDCProviderRequest{ | ||
Name: "test", | ||
Issuer: "https://localhost/auth", | ||
|
||
ClientID: "bloodhound", | ||
}). | ||
OnHandlerFunc(resources.CreateOIDCProvider). | ||
Require(). | ||
ResponseStatusCode(http.StatusInternalServerError) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
-- OIDC Provider | ||
CREATE TABLE IF NOT EXISTS oidc_providers | ||
( | ||
id BIGSERIAL PRIMARY KEY, | ||
name TEXT NOT NULL, | ||
client_id TEXT NOT NULL, | ||
issuer TEXT NOT NULL, | ||
|
||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT now(), | ||
created_at TIMESTAMP WITH TIME ZONE DEFAULT now(), | ||
|
||
UNIQUE (name) | ||
) |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright 2024 Specter Ops, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package database | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/specterops/bloodhound/src/model" | ||
) | ||
|
||
// OIDCProviderData defines the interface required to interact with the oidc_providers table | ||
type OIDCProviderData interface { | ||
CreateOIDCProvider(ctx context.Context, name, issuer, clientID string) (model.OIDCProvider, error) | ||
} | ||
|
||
// CreateOIDCProvider creates a new entry for an OIDC provider | ||
func (s *BloodhoundDB) CreateOIDCProvider(ctx context.Context, name, issuer, clientID string) (model.OIDCProvider, error) { | ||
provider := model.OIDCProvider{ | ||
Name: name, | ||
ClientID: clientID, | ||
Issuer: issuer, | ||
} | ||
|
||
return provider, CheckError(s.db.WithContext(ctx).Table("oidc_providers").Create(&provider)) | ||
} |
Oops, something went wrong.