go.temporal.io/server@v1.23.0/common/authorization/default_authorizer_test.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package authorization 26 27 import ( 28 "context" 29 "reflect" 30 "testing" 31 32 "github.com/golang/mock/gomock" 33 "github.com/stretchr/testify/require" 34 "github.com/stretchr/testify/suite" 35 "go.temporal.io/server/common/config" 36 ) 37 38 var ( 39 claimsNone = Claims{} 40 claimsNamespaceAdmin = Claims{ 41 Namespaces: map[string]Role{ 42 testNamespace: RoleAdmin, 43 }, 44 } 45 claimsNamespaceWriter = Claims{ 46 Namespaces: map[string]Role{ 47 testNamespace: RoleWriter, 48 }, 49 } 50 claimsNamespaceReader = Claims{ 51 Namespaces: map[string]Role{ 52 testNamespace: RoleReader, 53 }, 54 } 55 claimsBarAdmin = Claims{ 56 Namespaces: map[string]Role{ 57 "bar": RoleAdmin, 58 }, 59 } 60 claimsSystemAdmin = Claims{ 61 System: RoleAdmin, 62 } 63 claimsSystemWriter = Claims{ 64 System: RoleWriter, 65 } 66 claimsSystemReader = Claims{ 67 System: RoleReader, 68 } 69 targetNamespaceWriteBar = CallTarget{ 70 APIName: "/temporal.api.workflowservice.v1.WorkflowService/RespondWorkflowTaskCompleted", 71 Namespace: "bar", 72 } 73 targetNamespaceWriteBAR = CallTarget{ 74 APIName: "/temporal.api.workflowservice.v1.WorkflowService/RespondWorkflowTaskCompleted", 75 Namespace: "BAR", 76 } 77 targetOperatorNamespaceRead = CallTarget{ 78 APIName: "/temporal.api.operatorservice.v1.OperatorService/ListSearchAttributes", 79 Namespace: testNamespace, 80 } 81 targetGrpcHealthCheck = CallTarget{ 82 APIName: "/grpc.health.v1.Health/Check", 83 Namespace: "", 84 } 85 targetGetSystemInfo = CallTarget{ 86 APIName: "/temporal.api.workflowservice.v1.WorkflowService/GetSystemInfo", 87 Namespace: "", 88 } 89 targetStartWorkflow = CallTarget{ 90 APIName: "/temporal.api.workflowservice.v1.WorkflowService/StartWorkflowExecution", 91 Namespace: testNamespace, 92 } 93 targetAdminAPI = CallTarget{ 94 APIName: "/temporal.server.api.adminservice.v1.AdminService/AddSearchAttributes", 95 Namespace: testNamespace, 96 } 97 ) 98 99 type ( 100 defaultAuthorizerSuite struct { 101 suite.Suite 102 *require.Assertions 103 104 controller *gomock.Controller 105 authorizer Authorizer 106 } 107 ) 108 109 func TestDefaultAuthorizerSuite(t *testing.T) { 110 s := new(defaultAuthorizerSuite) 111 suite.Run(t, s) 112 } 113 114 func (s *defaultAuthorizerSuite) SetupTest() { 115 s.Assertions = require.New(s.T()) 116 s.controller = gomock.NewController(s.T()) 117 s.authorizer = NewDefaultAuthorizer() 118 } 119 120 func (s *defaultAuthorizerSuite) TearDownTest() { 121 s.controller.Finish() 122 } 123 124 func (s *defaultAuthorizerSuite) TestAuthorize() { 125 testCases := []struct { 126 Name string 127 Claims Claims 128 Target CallTarget 129 Decision Decision 130 }{ 131 // SystemAdmin is allowed on everything 132 {"SystemAdminOnFooBar", claimsSystemAdmin, targetNamespaceWriteBar, DecisionAllow}, 133 {"SystemAdminOnAdminAPI", claimsSystemAdmin, targetAdminAPI, DecisionAllow}, 134 {"SystemAdminOnStartWorkflow", claimsSystemAdmin, targetStartWorkflow, DecisionAllow}, 135 136 // SystemWriter is allowed on all read only APIs and non-admin APIs on every namespaces 137 {"SystemWriterOnFooBar", claimsSystemWriter, targetNamespaceWriteBar, DecisionAllow}, 138 {"SystemWriterOnAdminAPI", claimsSystemWriter, targetAdminAPI, DecisionDeny}, 139 {"SystemWriterOnStartWorkflow", claimsSystemWriter, targetStartWorkflow, DecisionAllow}, 140 141 // SystemReader is allowed on all read only APIs and blocked 142 {"SystemReaderOnFooBar", claimsSystemReader, targetNamespaceWriteBar, DecisionDeny}, 143 {"SystemReaderOnAdminAPI", claimsSystemReader, targetAdminAPI, DecisionDeny}, 144 {"SystemReaderOnStartWorkflow", claimsSystemReader, targetStartWorkflow, DecisionDeny}, 145 146 // NamespaceAdmin is allowed on admin service to their own namespaces (test-namespace) 147 {"NamespaceAdminOnAdminAPI", claimsNamespaceAdmin, targetAdminAPI, DecisionDeny}, 148 {"NamespaceAdminOnStartWorkflow", claimsNamespaceAdmin, targetStartWorkflow, DecisionAllow}, 149 {"NamespaceAdminOnFooBar", claimsNamespaceAdmin, targetNamespaceWriteBar, DecisionDeny}, // namespace mismatch 150 151 {"BarAdminOnFooBar", claimsBarAdmin, targetNamespaceWriteBar, DecisionAllow}, 152 {"BarAdminOnFooBAR", claimsBarAdmin, targetNamespaceWriteBAR, DecisionDeny}, // namespace case mismatch 153 154 // NamespaceWriter is not allowed on admin APIs 155 {"NamespaceWriterOnAdminAPI", claimsNamespaceWriter, targetAdminAPI, DecisionDeny}, 156 {"NamespaceWriterOnStartWorkflow", claimsNamespaceWriter, targetStartWorkflow, DecisionAllow}, 157 {"NamespaceWriterOnOperatorNamespaceRead", claimsNamespaceWriter, targetOperatorNamespaceRead, DecisionAllow}, 158 {"NamespaceWriterOnFooBar", claimsNamespaceWriter, targetNamespaceWriteBar, DecisionDeny}, // namespace mismatch 159 160 // NamespaceReader is allowed on read-only APIs on non admin service 161 {"NamespaceReaderOnAdminAPI", claimsNamespaceReader, targetAdminAPI, DecisionDeny}, 162 {"NamespaceReaderOnStartWorkflow", claimsNamespaceReader, targetStartWorkflow, DecisionDeny}, 163 {"NamespaceReaderOnFooBar", claimsNamespaceReader, targetNamespaceWriteBar, DecisionDeny}, // namespace mismatch 164 {"NamespaceReaderOnListWorkflow", claimsNamespaceReader, targetGetSystemInfo, DecisionAllow}, 165 {"NamespaceReaderOnOperatorNamespaceRead", claimsNamespaceReader, targetOperatorNamespaceRead, DecisionAllow}, 166 167 // healthcheck allowed to everyone 168 {"RoleNoneOnGetSystemInfo", claimsNone, targetGetSystemInfo, DecisionAllow}, 169 {"NamespaceReaderOnGetSystemInfo", claimsNamespaceReader, targetGetSystemInfo, DecisionAllow}, 170 {"RoleNoneOnHealthCheck", claimsNone, targetGrpcHealthCheck, DecisionAllow}, 171 {"NamespaceReaderOnHealthCheck", claimsNamespaceReader, targetGrpcHealthCheck, DecisionAllow}, 172 } 173 174 for _, tt := range testCases { 175 result, err := s.authorizer.Authorize(context.TODO(), &tt.Claims, &tt.Target) 176 s.NoError(err) 177 s.Equal(tt.Decision, result.Decision, "Failed case: %v", tt.Name) 178 } 179 } 180 181 func (s *defaultAuthorizerSuite) TestGetAuthorizerFromConfigNoop() { 182 s.testGetAuthorizerFromConfig("", true, reflect.TypeOf(&noopAuthorizer{})) 183 } 184 func (s *defaultAuthorizerSuite) TestGetAuthorizerFromConfigDefault() { 185 s.testGetAuthorizerFromConfig("default", true, reflect.TypeOf(&defaultAuthorizer{})) 186 } 187 func (s *defaultAuthorizerSuite) TestGetAuthorizerFromConfigUnknown() { 188 s.testGetAuthorizerFromConfig("foo", false, nil) 189 } 190 191 func (s *defaultAuthorizerSuite) testGetAuthorizerFromConfig(name string, valid bool, authorizerType reflect.Type) { 192 193 cfg := config.Authorization{Authorizer: name} 194 auth, err := GetAuthorizerFromConfig(&cfg) 195 if valid { 196 s.NoError(err) 197 s.NotNil(auth) 198 t := reflect.TypeOf(auth) 199 s.True(t == authorizerType) 200 } else { 201 s.Error(err) 202 s.Nil(auth) 203 } 204 }