Skip to content

Commit

Permalink
Merge pull request #185 from canonical/IAM-657-cobra-cli
Browse files Browse the repository at this point in the history
Introduce cobra CLI and basic authorization functionality
  • Loading branch information
nsklikas authored Jan 26, 2024
2 parents 42cd230 + e389386 commit 95d9275
Show file tree
Hide file tree
Showing 29 changed files with 818 additions and 88 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ vendor:
.PHONY: vendor

build: cmd/ui/dist
$(MAKE) -C cmd build
$(GO) build -o $(GO_BIN) ./
.PHONY: build

# plan is to use this as a probe, if folder is there target wont run and npm-build will skip
Expand Down
16 changes: 16 additions & 0 deletions cmd/admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cmd

import (
"github.com/spf13/cobra"
)

// adminCmd represents the admin command
var adminCmd = &cobra.Command{
Use: "admin",
Short: "Manage the Admin users",
Long: `Manage the Admin users.`,
}

func init() {
rootCmd.AddCommand(adminCmd)
}
31 changes: 31 additions & 0 deletions cmd/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cmd

import (
"fmt"

"github.com/spf13/cobra"
)

// createCmd represents the create command
var createCmd = &cobra.Command{
Use: "create",
Short: "Create an admin user",
Long: `Create an admin user.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("TODO")
},
}

func init() {
adminCmd.AddCommand(createCmd)

// Here you will define your flags and configuration settings.

// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// createCmd.PersistentFlags().String("foo", "", "A help for foo")

// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// createCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
69 changes: 69 additions & 0 deletions cmd/createFgaModel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package cmd

import (
"context"
"fmt"
"net/url"

"github.com/canonical/identity-platform-admin-ui/internal/authorization"
"github.com/canonical/identity-platform-admin-ui/internal/logging"
"github.com/canonical/identity-platform-admin-ui/internal/monitoring"
fga "github.com/canonical/identity-platform-admin-ui/internal/openfga"
"github.com/canonical/identity-platform-admin-ui/internal/tracing"
"github.com/openfga/go-sdk/client"
"github.com/spf13/cobra"
)

// createFgaModelCmd represents the createFgaModel command
var createFgaModelCmd = &cobra.Command{
Use: "create-fga-model",
Short: "Creates an openfga model",
Long: `Creates an openfga model`,
Run: func(cmd *cobra.Command, args []string) {
apiUrl, _ := cmd.Flags().GetString("fga-api-url")
apiToken, _ := cmd.Flags().GetString("fga-api-token")
storeId, _ := cmd.Flags().GetString("fga-store-id")
createModel(apiUrl, apiToken, storeId)
},
}

func init() {
rootCmd.AddCommand(createFgaModelCmd)

createFgaModelCmd.Flags().String("fga-api-url", "", "The openfga API URL")
createFgaModelCmd.Flags().String("fga-api-token", "", "The openfga API token")
createFgaModelCmd.Flags().String("fga-store-id", "", "The openfga store to create the model in")
createFgaModelCmd.MarkFlagRequired("fga-api-url")
createFgaModelCmd.MarkFlagRequired("fga-api-token")
createFgaModelCmd.MarkFlagRequired("fga-store-id")
}

func createModel(apiUrl, apiToken, storeId string) {
logger := logging.NewNoopLogger()
tracer := tracing.NewNoopTracer()
monitor := monitoring.NewNoopMonitor("", logger)
scheme, host, err := parseURL(apiUrl)
if err != nil {
panic(err)
}
cfg := fga.NewConfig(scheme, host, storeId, apiToken, "", false, tracer, monitor, logger)
fgaClient := fga.NewClient(cfg)
authModelReq := client.ClientWriteAuthorizationModelRequest{
TypeDefinitions: authorization.AuthModel.TypeDefinitions,
SchemaVersion: authorization.AuthModel.SchemaVersion,
Conditions: authorization.AuthModel.Conditions,
}
modelId, err := fgaClient.WriteModel(context.Background(), &authModelReq)
if err != nil {
panic(err)
}
fmt.Printf("Created model: %s\n", modelId)
}

func parseURL(s string) (string, string, error) {
u, err := url.Parse(s)
if err != nil {
return "", "", err
}
return u.Scheme, u.Host, nil
}
26 changes: 26 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cmd

import (
"os"

"github.com/spf13/cobra"
)

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "",
Short: "Identity Platform Admin UI",
Long: `An admin UI for the Canonical Identity Platform`,
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}

func init() {
}
52 changes: 35 additions & 17 deletions cmd/main.go → cmd/serve.go
Original file line number Diff line number Diff line change
@@ -1,50 +1,54 @@
package main
package cmd

import (
"context"
"fmt"
"net/http"
"os"
"os/signal"

"syscall"
"time"

"github.com/canonical/identity-platform-admin-ui/internal/authorization"
"github.com/canonical/identity-platform-admin-ui/internal/config"
ih "github.com/canonical/identity-platform-admin-ui/internal/hydra"
k8s "github.com/canonical/identity-platform-admin-ui/internal/k8s"
"github.com/kelseyhightower/envconfig"

"github.com/canonical/identity-platform-admin-ui/internal/config"
ik "github.com/canonical/identity-platform-admin-ui/internal/kratos"
"github.com/canonical/identity-platform-admin-ui/internal/logging"
"github.com/canonical/identity-platform-admin-ui/internal/monitoring/prometheus"
io "github.com/canonical/identity-platform-admin-ui/internal/oathkeeper"
"github.com/canonical/identity-platform-admin-ui/internal/openfga"
"github.com/canonical/identity-platform-admin-ui/internal/tracing"
"github.com/canonical/identity-platform-admin-ui/internal/version"
"github.com/canonical/identity-platform-admin-ui/pkg/idp"
"github.com/canonical/identity-platform-admin-ui/pkg/rules"
"github.com/canonical/identity-platform-admin-ui/pkg/schemas"
"github.com/canonical/identity-platform-admin-ui/pkg/web"
"github.com/kelseyhightower/envconfig"
"github.com/spf13/cobra"
)

func main() {
// serveCmd represents the serve command
var serveCmd = &cobra.Command{
Use: "serve",
Short: "Serve starts the web server",
Long: `Launch the web application, list of environment variables is available in the README.`,
Run: func(cmd *cobra.Command, args []string) {
serve()
},
}

func init() {
rootCmd.AddCommand(serveCmd)
}

func serve() {

specs := new(config.EnvSpec)

if err := envconfig.Process("", specs); err != nil {
panic(fmt.Errorf("issues with environment sourcing: %s", err))
}

flags := config.NewFlags()

switch {
case flags.ShowVersion:
fmt.Printf("App Version: %s\n", version.Version)
os.Exit(0)
default:
break
}

logger := logging.NewLogger(specs.LogLevel, specs.LogFile)

monitor := prometheus.NewMonitor("identity-admin-ui", logger)
Expand Down Expand Up @@ -76,6 +80,20 @@ func main() {

rulesConfig := rules.NewConfig(specs.RulesConfigMapName, specs.RulesConfigFileName, specs.RulesConfigMapNamespace, k8sCoreV1, oPublicClient.ApiApi())

var authzClient authorization.AuthzClientInterface
if specs.AuthorizationEnabled {
logger.Info("Authorization is enabled")
cfg := openfga.NewConfig(specs.ApiScheme, specs.ApiHost, specs.StoreId, specs.ApiToken, specs.AuthorizationModelId, specs.Debug, tracer, monitor, logger)
authzClient = openfga.NewClient(cfg)
} else {
logger.Info("Authorization is disabled, using noop authorizer")
authzClient = openfga.NewNoopClient(tracer, monitor, logger)
}
authorizer := authorization.NewAuthorizer(authzClient, tracer, monitor, logger)
if authorizer.ValidateModel(context.Background()) != nil {
panic("Invalid authorization model provided")
}

router := web.NewRouter(idpConfig, schemasConfig, rulesConfig, hAdminClient, kAdminClient, tracer, monitor, logger)

logger.Infof("Starting server on port %v", specs.Port)
Expand Down
22 changes: 22 additions & 0 deletions cmd/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd

import (
"fmt"

"github.com/canonical/identity-platform-admin-ui/internal/version"
"github.com/spf13/cobra"
)

// versionCmd represents the version command
var versionCmd = &cobra.Command{
Use: "version",
Short: "Get the application's version.",
Long: `Get the application's version.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("App Version: %s\n", version.Version)
},
}

func init() {
rootCmd.AddCommand(versionCmd)
}
7 changes: 7 additions & 0 deletions deployments/helm/openfga/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
datastore:
engine: postgres
uri: "postgres://iam:[email protected]/openfga?sslmode=disable"
authn:
preshared:
keys:
- "42"
1 change: 1 addition & 0 deletions deployments/helm/postgresql/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ primary:
init.sql: |
CREATE DATABASE kratos;
CREATE DATABASE hydra;
CREATE DATABASE openfga;
auth:
database: "iam"
Expand Down
4 changes: 2 additions & 2 deletions deployments/kubectl/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ spec:
selector:
matchLabels:
app: identity-platform-admin-ui
strategy:
type: Recreate
strategy:
type: Recreate
template:
metadata:
labels:
Expand Down
41 changes: 28 additions & 13 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
module github.com/canonical/identity-platform-admin-ui

go 1.21
go 1.21.3

toolchain go1.21.4

require (
github.com/go-chi/chi/v5 v5.0.10
github.com/go-chi/cors v1.2.1
github.com/google/uuid v1.4.0
github.com/kelseyhightower/envconfig v1.4.0
github.com/openfga/go-sdk v0.3.3
github.com/openfga/language/pkg/go v0.0.0-20240122114256-aaa86ab89379
github.com/ory/hydra-client-go/v2 v2.1.1
github.com/ory/kratos-client-go v1.0.0
github.com/ory/oathkeeper-client-go v0.40.6
github.com/prometheus/client_golang v1.17.0
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.8.4
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0
go.opentelemetry.io/contrib/propagators/jaeger v1.20.0
Expand All @@ -23,6 +28,7 @@ require (
go.opentelemetry.io/otel/trace v1.19.0
go.uber.org/mock v0.3.0
go.uber.org/zap v1.26.0
google.golang.org/protobuf v1.32.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.28.3
Expand All @@ -31,11 +37,13 @@ require (
)

require (
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/go-logr/logr v1.2.4 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
Expand All @@ -45,35 +53,42 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20221010195024-131d412537ea // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/openfga/api/proto v0.0.0-20231222042535-3037910c90c0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.11.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.opentelemetry.io/otel/metric v1.19.0 // indirect
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.11.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/oauth2 v0.13.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
google.golang.org/grpc v1.58.2 // indirect
google.golang.org/protobuf v1.31.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
google.golang.org/grpc v1.60.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.100.1 // indirect
Expand Down
Loading

0 comments on commit 95d9275

Please sign in to comment.