This is an automated email from the ASF dual-hosted git repository.

tison pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-client-go.git


The following commit(s) were added to refs/heads/master by this push:
     new 4ebb3c7  Add data url format to read the key file (#883)
4ebb3c7 is described below

commit 4ebb3c7212e44b27e0096357eff510c51e556d40
Author: Zixuan Liu <[email protected]>
AuthorDate: Wed Nov 16 15:51:59 2022 +0800

    Add data url format to read the key file (#883)
    
    Signed-off-by: Zixuan Liu <[email protected]>
---
 oauth2/client_credentials_provider.go      |  6 +++
 oauth2/client_credentials_provider_test.go | 78 ++++++++++++++++++++++++++++++
 oauth2/data_url.go                         | 70 +++++++++++++++++++++++++++
 oauth2/data_url_test.go                    | 58 ++++++++++++++++++++++
 4 files changed, 212 insertions(+)

diff --git a/oauth2/client_credentials_provider.go 
b/oauth2/client_credentials_provider.go
index c112225..5230ca3 100644
--- a/oauth2/client_credentials_provider.go
+++ b/oauth2/client_credentials_provider.go
@@ -57,6 +57,12 @@ func (k *KeyFileProvider) GetClientCredentials() (*KeyFile, 
error) {
                keyFile, err = ioutil.ReadFile(filename)
        case strings.HasPrefix(k.KeyFile, DATA):
                keyFile = []byte(strings.TrimPrefix(k.KeyFile, DATA))
+       case strings.HasPrefix(k.KeyFile, "data:"):
+               url, err := newDataURL(k.KeyFile)
+               if err != nil {
+                       return nil, err
+               }
+               keyFile = url.Data
        default:
                keyFile, err = ioutil.ReadFile(k.KeyFile)
        }
diff --git a/oauth2/client_credentials_provider_test.go 
b/oauth2/client_credentials_provider_test.go
new file mode 100644
index 0000000..f47967b
--- /dev/null
+++ b/oauth2/client_credentials_provider_test.go
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 oauth2
+
+import (
+       "encoding/base64"
+       "encoding/json"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestNewClientCredentialsProviderFromKeyFile(t *testing.T) {
+       oauthType := "TYPE"
+       clientID := "CLIENT_ID"
+       ClientSecret := "CLIENT_SECRET"
+       ClientEmail := "CLIENT_EMAIL"
+       IssuerURL := "ISSUER_URL"
+       keyFile := &KeyFile{
+               Type:         oauthType,
+               ClientID:     clientID,
+               ClientSecret: ClientSecret,
+               ClientEmail:  ClientEmail,
+               IssuerURL:    IssuerURL,
+       }
+
+       b, err := json.Marshal(keyFile)
+       require.NoError(t, err)
+       tmpFile, err := ioutil.TempFile("", "key-file")
+       require.NoError(t, err)
+       defer func(name string) {
+               _ = os.Remove(name)
+       }(tmpFile.Name())
+       _, err = tmpFile.Write(b)
+       require.NoError(t, err)
+
+       jsonData := string(b)
+       base64Data := base64.StdEncoding.EncodeToString(b)
+
+       assertCredentials(t, fmt.Sprintf("file://%s", tmpFile.Name()), keyFile)
+       assertCredentials(t, fmt.Sprintf("data://%s", jsonData), keyFile)
+       assertCredentials(t, fmt.Sprintf("data:,%s", jsonData), keyFile)
+       assertCredentials(t, fmt.Sprintf("data:application/json,%s", jsonData), 
keyFile)
+       assertCredentials(t, fmt.Sprintf("data:;base64,%s", base64Data), 
keyFile)
+       assertCredentials(t, fmt.Sprintf("data:application/json;base64,%s", 
base64Data), keyFile)
+}
+
+func TestNewInvalidClientCredentialsProviderFromKeyFile(t *testing.T) {
+       p := NewClientCredentialsProviderFromKeyFile("data:application/data,hi")
+       _, err := p.GetClientCredentials()
+       require.Error(t, err)
+}
+
+func assertCredentials(t *testing.T, keyfile string, expected *KeyFile) {
+       p := NewClientCredentialsProviderFromKeyFile(keyfile)
+       clientCredentials, err := p.GetClientCredentials()
+       require.NoError(t, err)
+       assert.Equal(t, expected, clientCredentials)
+}
diff --git a/oauth2/data_url.go b/oauth2/data_url.go
new file mode 100644
index 0000000..8d711f8
--- /dev/null
+++ b/oauth2/data_url.go
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 oauth2
+
+import (
+       "encoding/base64"
+       "errors"
+       "regexp"
+)
+
+var errDataURLInvalid = errors.New("invalid data URL")
+
+// https://datatracker.ietf.org/doc/html/rfc2397
+var dataURLRegex = 
regexp.MustCompile("^data:(?P<mimetype>[^;,]+)?(;(?P<charset>charset=[^;,]+))?" 
+
+       "(;(?P<base64>base64))?,(?P<data>.+)")
+
+type dataURL struct {
+       url      string
+       Mimetype string
+       Data     []byte
+}
+
+func newDataURL(url string) (*dataURL, error) {
+       if !dataURLRegex.Match([]byte(url)) {
+               return nil, errDataURLInvalid
+       }
+
+       match := dataURLRegex.FindStringSubmatch(url)
+       if len(match) != 7 {
+               return nil, errDataURLInvalid
+       }
+
+       dataURL := &dataURL{
+               url: url,
+       }
+
+       mimetype := match[dataURLRegex.SubexpIndex("mimetype")]
+       if mimetype == "" {
+               mimetype = "text/plain"
+       }
+       dataURL.Mimetype = mimetype
+
+       data := match[dataURLRegex.SubexpIndex("data")]
+       if match[dataURLRegex.SubexpIndex("base64")] == "" {
+               dataURL.Data = []byte(data)
+       } else {
+               data, err := base64.StdEncoding.DecodeString(data)
+               if err != nil {
+                       return nil, err
+               }
+               dataURL.Data = data
+       }
+
+       return dataURL, nil
+}
diff --git a/oauth2/data_url_test.go b/oauth2/data_url_test.go
new file mode 100644
index 0000000..8bdc880
--- /dev/null
+++ b/oauth2/data_url_test.go
@@ -0,0 +1,58 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you 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 oauth2
+
+import (
+       "encoding/base64"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestNewDataURL(t *testing.T) {
+       rawURL := "data:,test"
+       url, err := newDataURL(rawURL)
+       require.NoError(t, err)
+       assert.Equal(t, "text/plain", url.Mimetype)
+       assert.Equal(t, "test", string(url.Data))
+
+       rawURL = "data:;base64," + 
base64.StdEncoding.EncodeToString([]byte("test"))
+       url, err = newDataURL(rawURL)
+       require.NoError(t, err)
+       assert.Equal(t, "text/plain", url.Mimetype)
+       assert.Equal(t, "test", string(url.Data))
+
+       rawURL = "data:application/json,test"
+       url, err = newDataURL(rawURL)
+       require.NoError(t, err)
+       assert.Equal(t, "application/json", url.Mimetype)
+       assert.Equal(t, "test", string(url.Data))
+
+       rawURL = "data:application/json;base64," + 
base64.StdEncoding.EncodeToString([]byte("test"))
+       url, err = newDataURL(rawURL)
+       require.NoError(t, err)
+       assert.Equal(t, "application/json", url.Mimetype)
+       assert.Equal(t, "test", string(url.Data))
+
+       rawURL = "data://test"
+       url, err = newDataURL(rawURL)
+       require.Nil(t, url)
+       assert.Error(t, err)
+       assert.EqualError(t, errDataURLInvalid, err.Error())
+}

Reply via email to