github.com/shogo82148/goa-v1@v1.6.2/design/apidsl/security_test.go (about) 1 package apidsl_test 2 3 import ( 4 . "github.com/onsi/ginkgo" 5 . "github.com/onsi/gomega" 6 "github.com/shogo82148/goa-v1/design" 7 "github.com/shogo82148/goa-v1/design/apidsl" 8 "github.com/shogo82148/goa-v1/dslengine" 9 ) 10 11 var _ = Describe("Security", func() { 12 BeforeEach(func() { 13 dslengine.Reset() 14 }) 15 16 It("should have no security DSL when none are defined", func() { 17 apidsl.API("secure", nil) 18 dslengine.Run() 19 Ω(design.Design.SecuritySchemes).Should(BeNil()) 20 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 21 }) 22 23 It("should be the fully valid and well defined, live on the happy path", func() { 24 apidsl.API("secure", func() { 25 apidsl.Host("example.com") 26 apidsl.Scheme("http") 27 28 apidsl.BasicAuthSecurity("basic_authz", func() { 29 apidsl.Description("desc") 30 }) 31 32 apidsl.OAuth2Security("googAuthz", func() { 33 apidsl.Description("desc") 34 apidsl.AccessCodeFlow("/auth", "/token") 35 apidsl.Scope("user:read", "Read users") 36 }) 37 38 apidsl.APIKeySecurity("a_key", func() { 39 apidsl.Description("desc") 40 apidsl.Query("access_token") 41 }) 42 43 apidsl.JWTSecurity("jwt", func() { 44 apidsl.Description("desc") 45 apidsl.Header("Authorization") 46 apidsl.TokenURL("/token") 47 apidsl.Scope("user:read", "Read users") 48 apidsl.Scope("user:write", "Write users") 49 }) 50 }) 51 52 dslengine.Run() 53 54 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 55 Ω(design.Design.SecuritySchemes).Should(HaveLen(4)) 56 57 Ω(design.Design.SecuritySchemes[0].Kind).Should(Equal(design.BasicAuthSecurityKind)) 58 Ω(design.Design.SecuritySchemes[0].Description).Should(Equal("desc")) 59 60 Ω(design.Design.SecuritySchemes[1].Kind).Should(Equal(design.OAuth2SecurityKind)) 61 Ω(design.Design.SecuritySchemes[1].AuthorizationURL).Should(Equal("http://example.com/auth")) 62 Ω(design.Design.SecuritySchemes[1].TokenURL).Should(Equal("http://example.com/token")) 63 Ω(design.Design.SecuritySchemes[1].Flow).Should(Equal("accessCode")) 64 65 Ω(design.Design.SecuritySchemes[2].Kind).Should(Equal(design.APIKeySecurityKind)) 66 Ω(design.Design.SecuritySchemes[2].In).Should(Equal("query")) 67 Ω(design.Design.SecuritySchemes[2].Name).Should(Equal("access_token")) 68 69 Ω(design.Design.SecuritySchemes[3].Kind).Should(Equal(design.JWTSecurityKind)) 70 Ω(design.Design.SecuritySchemes[3].TokenURL).Should(Equal("http://example.com/token")) 71 Ω(design.Design.SecuritySchemes[3].Scopes).Should(HaveLen(2)) 72 }) 73 74 Context("with basic security", func() { 75 It("should fail because of duplicate In declaration", func() { 76 apidsl.API("", func() { 77 apidsl.BasicAuthSecurity("broken_basic_authz", func() { 78 apidsl.Description("desc") 79 apidsl.Header("Authorization") 80 apidsl.Query("access_token") 81 }) 82 }) 83 dslengine.Run() 84 Ω(dslengine.Errors).Should(HaveOccurred()) 85 }) 86 87 It("should fail because of invalid declaration of OAuth2Flow", func() { 88 apidsl.API("", func() { 89 apidsl.BasicAuthSecurity("broken_basic_authz", func() { 90 apidsl.Description("desc") 91 apidsl.ImplicitFlow("invalid") 92 }) 93 }) 94 dslengine.Run() 95 Ω(dslengine.Errors).Should(HaveOccurred()) 96 }) 97 98 It("should fail because of invalid declaration of TokenURL", func() { 99 apidsl.API("", func() { 100 apidsl.BasicAuthSecurity("broken_basic_authz", func() { 101 apidsl.Description("desc") 102 apidsl.TokenURL("/token") 103 }) 104 }) 105 dslengine.Run() 106 Ω(dslengine.Errors).Should(HaveOccurred()) 107 }) 108 109 It("should fail because of invalid declaration of TokenURL", func() { 110 apidsl.API("", func() { 111 apidsl.BasicAuthSecurity("broken_basic_authz", func() { 112 apidsl.Description("desc") 113 apidsl.TokenURL("in valid") 114 }) 115 }) 116 dslengine.Run() 117 Ω(dslengine.Errors).Should(HaveOccurred()) 118 }) 119 120 It("should fail because of invalid declaration of Header", func() { 121 apidsl.API("", func() { 122 apidsl.BasicAuthSecurity("broken_basic_authz", func() { 123 apidsl.Description("desc") 124 apidsl.Header("invalid") 125 }) 126 }) 127 dslengine.Run() 128 Ω(dslengine.Errors).Should(HaveOccurred()) 129 }) 130 }) 131 132 Context("with oauth2 security", func() { 133 It("should pass with valid values when well defined", func() { 134 apidsl.API("", func() { 135 apidsl.Host("example.com") 136 apidsl.Scheme("http") 137 apidsl.OAuth2Security("googAuthz", func() { 138 apidsl.Description("Use Goog's Auth") 139 apidsl.AccessCodeFlow("/auth", "/token") 140 apidsl.Scope("scope:1", "Desc 1") 141 apidsl.Scope("scope:2", "Desc 2") 142 }) 143 }) 144 apidsl.Resource("one", func() { 145 apidsl.Action("first", func() { 146 apidsl.Routing(apidsl.GET("/first")) 147 apidsl.Security("googAuthz", func() { 148 apidsl.Scope("scope:1") 149 }) 150 }) 151 }) 152 153 dslengine.Run() 154 155 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 156 Ω(design.Design.SecuritySchemes).Should(HaveLen(1)) 157 scheme := design.Design.SecuritySchemes[0] 158 Ω(scheme.Description).Should(Equal("Use Goog's Auth")) 159 Ω(scheme.AuthorizationURL).Should(Equal("http://example.com/auth")) 160 Ω(scheme.TokenURL).Should(Equal("http://example.com/token")) 161 Ω(scheme.Flow).Should(Equal("accessCode")) 162 Ω(scheme.Scopes["scope:1"]).Should(Equal("Desc 1")) 163 Ω(scheme.Scopes["scope:2"]).Should(Equal("Desc 2")) 164 }) 165 166 It("should fail because of invalid declaration of Header", func() { 167 apidsl.API("", func() { 168 apidsl.OAuth2Security("googAuthz", func() { 169 apidsl.Header("invalid") 170 }) 171 }) 172 dslengine.Run() 173 Ω(dslengine.Errors).Should(HaveOccurred()) 174 }) 175 176 }) 177 178 Context("with resources and actions", func() { 179 It("should fallback properly to lower-level security", func() { 180 apidsl.API("", func() { 181 apidsl.JWTSecurity("jwt", func() { 182 apidsl.TokenURL("/token") 183 apidsl.Scope("read", "Read") 184 apidsl.Scope("write", "Write") 185 }) 186 apidsl.BasicAuthSecurity("password") 187 188 apidsl.Security("jwt") 189 }) 190 apidsl.Resource("one", func() { 191 apidsl.Action("first", func() { 192 apidsl.Routing(apidsl.GET("/first")) 193 apidsl.NoSecurity() 194 }) 195 apidsl.Action("second", func() { 196 apidsl.Routing(apidsl.GET("/second")) 197 }) 198 }) 199 apidsl.Resource("two", func() { 200 apidsl.Security("password") 201 202 apidsl.Action("third", func() { 203 apidsl.Routing(apidsl.GET("/third")) 204 }) 205 apidsl.Action("fourth", func() { 206 apidsl.Routing(apidsl.GET("/fourth")) 207 apidsl.Security("jwt") 208 }) 209 }) 210 apidsl.Resource("three", func() { 211 apidsl.Action("fifth", func() { 212 apidsl.Routing(apidsl.GET("/fifth")) 213 }) 214 }) 215 apidsl.Resource("auth", func() { 216 apidsl.NoSecurity() 217 218 apidsl.Action("auth", func() { 219 apidsl.Routing(apidsl.GET("/auth")) 220 }) 221 apidsl.Action("refresh", func() { 222 apidsl.Routing(apidsl.GET("/refresh")) 223 apidsl.Security("jwt") 224 }) 225 }) 226 227 dslengine.Run() 228 229 Ω(dslengine.Errors).ShouldNot(HaveOccurred()) 230 Ω(design.Design.SecuritySchemes).Should(HaveLen(2)) 231 Ω(design.Design.Resources["one"].Actions["first"].Security).Should(BeNil()) 232 Ω(design.Design.Resources["one"].Actions["second"].Security.Scheme.SchemeName).Should(Equal("jwt")) 233 Ω(design.Design.Resources["two"].Actions["third"].Security.Scheme.SchemeName).Should(Equal("password")) 234 Ω(design.Design.Resources["two"].Actions["fourth"].Security.Scheme.SchemeName).Should(Equal("jwt")) 235 Ω(design.Design.Resources["three"].Actions["fifth"].Security.Scheme.SchemeName).Should(Equal("jwt")) 236 Ω(design.Design.Resources["auth"].Actions["auth"].Security).Should(BeNil()) 237 Ω(design.Design.Resources["auth"].Actions["refresh"].Security.Scheme.SchemeName).Should(Equal("jwt")) 238 }) 239 }) 240 })