summaryrefslogtreecommitdiff
path: root/vendor/gopkg.in/square/go-jose.v2/jwt/builder.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/square/go-jose.v2/jwt/builder.go')
-rw-r--r--vendor/gopkg.in/square/go-jose.v2/jwt/builder.go334
1 files changed, 334 insertions, 0 deletions
diff --git a/vendor/gopkg.in/square/go-jose.v2/jwt/builder.go b/vendor/gopkg.in/square/go-jose.v2/jwt/builder.go
new file mode 100644
index 000000000..686ec80a4
--- /dev/null
+++ b/vendor/gopkg.in/square/go-jose.v2/jwt/builder.go
@@ -0,0 +1,334 @@
+/*-
+ * Copyright 2016 Zbigniew Mandziejewicz
+ * Copyright 2016 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * 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.
+ */
+
+package jwt
+
+import (
+ "bytes"
+ "reflect"
+
+ "gopkg.in/square/go-jose.v2/json"
+
+ "gopkg.in/square/go-jose.v2"
+)
+
+// Builder is a utility for making JSON Web Tokens. Calls can be chained, and
+// errors are accumulated until the final call to CompactSerialize/FullSerialize.
+type Builder interface {
+ // Claims encodes claims into JWE/JWS form. Multiple calls will merge claims
+ // into single JSON object. If you are passing private claims, make sure to set
+ // struct field tags to specify the name for the JSON key to be used when
+ // serializing.
+ Claims(i interface{}) Builder
+ // Token builds a JSONWebToken from provided data.
+ Token() (*JSONWebToken, error)
+ // FullSerialize serializes a token using the full serialization format.
+ FullSerialize() (string, error)
+ // CompactSerialize serializes a token using the compact serialization format.
+ CompactSerialize() (string, error)
+}
+
+// NestedBuilder is a utility for making Signed-Then-Encrypted JSON Web Tokens.
+// Calls can be chained, and errors are accumulated until final call to
+// CompactSerialize/FullSerialize.
+type NestedBuilder interface {
+ // Claims encodes claims into JWE/JWS form. Multiple calls will merge claims
+ // into single JSON object. If you are passing private claims, make sure to set
+ // struct field tags to specify the name for the JSON key to be used when
+ // serializing.
+ Claims(i interface{}) NestedBuilder
+ // Token builds a NestedJSONWebToken from provided data.
+ Token() (*NestedJSONWebToken, error)
+ // FullSerialize serializes a token using the full serialization format.
+ FullSerialize() (string, error)
+ // CompactSerialize serializes a token using the compact serialization format.
+ CompactSerialize() (string, error)
+}
+
+type builder struct {
+ payload map[string]interface{}
+ err error
+}
+
+type signedBuilder struct {
+ builder
+ sig jose.Signer
+}
+
+type encryptedBuilder struct {
+ builder
+ enc jose.Encrypter
+}
+
+type nestedBuilder struct {
+ builder
+ sig jose.Signer
+ enc jose.Encrypter
+}
+
+// Signed creates builder for signed tokens.
+func Signed(sig jose.Signer) Builder {
+ return &signedBuilder{
+ sig: sig,
+ }
+}
+
+// Encrypted creates builder for encrypted tokens.
+func Encrypted(enc jose.Encrypter) Builder {
+ return &encryptedBuilder{
+ enc: enc,
+ }
+}
+
+// SignedAndEncrypted creates builder for signed-then-encrypted tokens.
+// ErrInvalidContentType will be returned if encrypter doesn't have JWT content type.
+func SignedAndEncrypted(sig jose.Signer, enc jose.Encrypter) NestedBuilder {
+ if contentType, _ := enc.Options().ExtraHeaders[jose.HeaderContentType].(jose.ContentType); contentType != "JWT" {
+ return &nestedBuilder{
+ builder: builder{
+ err: ErrInvalidContentType,
+ },
+ }
+ }
+ return &nestedBuilder{
+ sig: sig,
+ enc: enc,
+ }
+}
+
+func (b builder) claims(i interface{}) builder {
+ if b.err != nil {
+ return b
+ }
+
+ m, ok := i.(map[string]interface{})
+ switch {
+ case ok:
+ return b.merge(m)
+ case reflect.Indirect(reflect.ValueOf(i)).Kind() == reflect.Struct:
+ m, err := normalize(i)
+ if err != nil {
+ return builder{
+ err: err,
+ }
+ }
+ return b.merge(m)
+ default:
+ return builder{
+ err: ErrInvalidClaims,
+ }
+ }
+}
+
+func normalize(i interface{}) (map[string]interface{}, error) {
+ m := make(map[string]interface{})
+
+ raw, err := json.Marshal(i)
+ if err != nil {
+ return nil, err
+ }
+
+ d := json.NewDecoder(bytes.NewReader(raw))
+ d.UseNumber()
+
+ if err := d.Decode(&m); err != nil {
+ return nil, err
+ }
+
+ return m, nil
+}
+
+func (b *builder) merge(m map[string]interface{}) builder {
+ p := make(map[string]interface{})
+ for k, v := range b.payload {
+ p[k] = v
+ }
+ for k, v := range m {
+ p[k] = v
+ }
+
+ return builder{
+ payload: p,
+ }
+}
+
+func (b *builder) token(p func(interface{}) ([]byte, error), h []jose.Header) (*JSONWebToken, error) {
+ return &JSONWebToken{
+ payload: p,
+ Headers: h,
+ }, nil
+}
+
+func (b *signedBuilder) Claims(i interface{}) Builder {
+ return &signedBuilder{
+ builder: b.builder.claims(i),
+ sig: b.sig,
+ }
+}
+
+func (b *signedBuilder) Token() (*JSONWebToken, error) {
+ sig, err := b.sign()
+ if err != nil {
+ return nil, err
+ }
+
+ h := make([]jose.Header, len(sig.Signatures))
+ for i, v := range sig.Signatures {
+ h[i] = v.Header
+ }
+
+ return b.builder.token(sig.Verify, h)
+}
+
+func (b *signedBuilder) CompactSerialize() (string, error) {
+ sig, err := b.sign()
+ if err != nil {
+ return "", err
+ }
+
+ return sig.CompactSerialize()
+}
+
+func (b *signedBuilder) FullSerialize() (string, error) {
+ sig, err := b.sign()
+ if err != nil {
+ return "", err
+ }
+
+ return sig.FullSerialize(), nil
+}
+
+func (b *signedBuilder) sign() (*jose.JSONWebSignature, error) {
+ if b.err != nil {
+ return nil, b.err
+ }
+
+ p, err := json.Marshal(b.payload)
+ if err != nil {
+ return nil, err
+ }
+
+ return b.sig.Sign(p)
+}
+
+func (b *encryptedBuilder) Claims(i interface{}) Builder {
+ return &encryptedBuilder{
+ builder: b.builder.claims(i),
+ enc: b.enc,
+ }
+}
+
+func (b *encryptedBuilder) CompactSerialize() (string, error) {
+ enc, err := b.encrypt()
+ if err != nil {
+ return "", err
+ }
+
+ return enc.CompactSerialize()
+}
+
+func (b *encryptedBuilder) FullSerialize() (string, error) {
+ enc, err := b.encrypt()
+ if err != nil {
+ return "", err
+ }
+
+ return enc.FullSerialize(), nil
+}
+
+func (b *encryptedBuilder) Token() (*JSONWebToken, error) {
+ enc, err := b.encrypt()
+ if err != nil {
+ return nil, err
+ }
+
+ return b.builder.token(enc.Decrypt, []jose.Header{enc.Header})
+}
+
+func (b *encryptedBuilder) encrypt() (*jose.JSONWebEncryption, error) {
+ if b.err != nil {
+ return nil, b.err
+ }
+
+ p, err := json.Marshal(b.payload)
+ if err != nil {
+ return nil, err
+ }
+
+ return b.enc.Encrypt(p)
+}
+
+func (b *nestedBuilder) Claims(i interface{}) NestedBuilder {
+ return &nestedBuilder{
+ builder: b.builder.claims(i),
+ sig: b.sig,
+ enc: b.enc,
+ }
+}
+
+func (b *nestedBuilder) Token() (*NestedJSONWebToken, error) {
+ enc, err := b.signAndEncrypt()
+ if err != nil {
+ return nil, err
+ }
+
+ return &NestedJSONWebToken{
+ enc: enc,
+ Headers: []jose.Header{enc.Header},
+ }, nil
+}
+
+func (b *nestedBuilder) CompactSerialize() (string, error) {
+ enc, err := b.signAndEncrypt()
+ if err != nil {
+ return "", err
+ }
+
+ return enc.CompactSerialize()
+}
+
+func (b *nestedBuilder) FullSerialize() (string, error) {
+ enc, err := b.signAndEncrypt()
+ if err != nil {
+ return "", err
+ }
+
+ return enc.FullSerialize(), nil
+}
+
+func (b *nestedBuilder) signAndEncrypt() (*jose.JSONWebEncryption, error) {
+ if b.err != nil {
+ return nil, b.err
+ }
+
+ p, err := json.Marshal(b.payload)
+ if err != nil {
+ return nil, err
+ }
+
+ sig, err := b.sig.Sign(p)
+ if err != nil {
+ return nil, err
+ }
+
+ p2, err := sig.CompactSerialize()
+ if err != nil {
+ return nil, err
+ }
+
+ return b.enc.Encrypt([]byte(p2))
+}