github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/pfsagentd/pfsagentd-swift-auth-plugin/main.go (about)

     1  // Copyright (c) 2015-2021, NVIDIA CORPORATION.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package main
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"os"
    12  	"strings"
    13  
    14  	"github.com/swiftstack/ProxyFS/version"
    15  )
    16  
    17  type authInStruct struct {
    18  	AuthURL  string
    19  	AuthUser string
    20  	AuthKey  string
    21  	Account  string
    22  }
    23  
    24  type authOutStruct struct {
    25  	AuthToken  string
    26  	StorageURL string
    27  }
    28  
    29  const (
    30  	stdinReadSize = 1
    31  )
    32  
    33  func main() {
    34  	var (
    35  		authIn         authInStruct
    36  		err            error
    37  		plugInEnvName  string
    38  		plugInEnvValue string
    39  		stdinReadBuf   []byte
    40  	)
    41  
    42  	switch len(os.Args) {
    43  	case 0:
    44  		fmt.Fprintf(os.Stderr, "Logic error... len(os.Args) cannot be zero\n")
    45  		os.Exit(1)
    46  	case 1:
    47  		fmt.Fprintf(os.Stderr, "Missing PlugInEnvName\n")
    48  		os.Exit(1)
    49  	case 2:
    50  		plugInEnvName = os.Args[1]
    51  	default:
    52  		fmt.Fprintf(os.Stderr, "Superfluous arguments (beyond PlugInEnvName) supplied: %v\n", os.Args[2:])
    53  		os.Exit(1)
    54  	}
    55  
    56  	plugInEnvValue = os.Getenv(plugInEnvName)
    57  
    58  	err = json.Unmarshal([]byte(plugInEnvValue), &authIn)
    59  	if nil != err {
    60  		fmt.Fprintf(os.Stderr, "json.Unmarshal(\"%s\",) failed: %v\n", plugInEnvValue, err)
    61  		os.Exit(1)
    62  	}
    63  
    64  	performAuth(&authIn)
    65  
    66  	stdinReadBuf = make([]byte, stdinReadSize)
    67  
    68  	for {
    69  		stdinReadBuf = stdinReadBuf[:stdinReadSize]
    70  		_, err = os.Stdin.Read(stdinReadBuf)
    71  		if nil == err {
    72  			performAuth(&authIn)
    73  		} else {
    74  			if io.EOF == err {
    75  				os.Exit(0)
    76  			}
    77  			fmt.Fprintf(os.Stderr, "os.Stdin.Read(stdinReadBuf) failed: %v\n", err)
    78  			os.Exit(1)
    79  		}
    80  	}
    81  }
    82  
    83  func performAuth(authIn *authInStruct) {
    84  	var (
    85  		authOut         *authOutStruct
    86  		authOutJSON     []byte
    87  		authRequest     *http.Request
    88  		authResponse    *http.Response
    89  		err             error
    90  		storageURLSplit []string
    91  	)
    92  
    93  	authRequest, err = http.NewRequest("GET", authIn.AuthURL, nil)
    94  	if nil != err {
    95  		fmt.Fprintf(os.Stderr, "http.NewRequest(\"GET\", \"%s\", nil) failed: %v\n", authIn.AuthURL, err)
    96  		os.Exit(1)
    97  	}
    98  
    99  	authRequest.Header.Add("X-Auth-User", authIn.AuthUser)
   100  	authRequest.Header.Add("X-Auth-Key", authIn.AuthKey)
   101  
   102  	authRequest.Header.Add("User-Agent", "PFSAgent-Auth "+version.ProxyFSVersion)
   103  
   104  	authResponse, err = http.DefaultClient.Do(authRequest)
   105  	if nil != err {
   106  		fmt.Fprintf(os.Stderr, "http.DefaultClient.Do(authRequest) failed: %v\n", err)
   107  		os.Exit(1)
   108  	}
   109  
   110  	if http.StatusOK != authResponse.StatusCode {
   111  		fmt.Fprintf(os.Stderr, "authResponse.Status unexpecte: %v\n", authResponse.Status)
   112  		os.Exit(1)
   113  	}
   114  
   115  	authOut = &authOutStruct{
   116  		AuthToken:  authResponse.Header.Get("X-Auth-Token"),
   117  		StorageURL: authResponse.Header.Get("X-Storage-Url"),
   118  	}
   119  
   120  	if strings.HasPrefix(authIn.AuthURL, "https://") && strings.HasPrefix(authOut.StorageURL, "http://") {
   121  		// We need to correct for the case where AuthURL starts with "https://""
   122  		// but the Swift Proxy is behind a TLS terminating proxy. In this case,
   123  		// Swift Proxy auth will actually see an AuthURL starting with "http://""
   124  		// and respond with a StorageURL starting with "http://"".
   125  
   126  		authOut.StorageURL = strings.Replace(authOut.StorageURL, "http://", "https://", 1)
   127  	}
   128  
   129  	storageURLSplit = strings.Split(authOut.StorageURL, "/")
   130  
   131  	storageURLSplit[3] = "proxyfs"
   132  	storageURLSplit[4] = authIn.Account
   133  
   134  	authOut.StorageURL = strings.Join(storageURLSplit, "/")
   135  
   136  	authOutJSON, err = json.Marshal(authOut)
   137  	if nil != err {
   138  		fmt.Fprintf(os.Stderr, "json.Marshal(authOut) failed: %v\n", err)
   139  		os.Exit(1)
   140  	}
   141  
   142  	_, err = os.Stdout.Write(authOutJSON)
   143  	if nil != err {
   144  		fmt.Fprintf(os.Stderr, "os.Stdout.Write(authOutJSON) failed: %v\n", err)
   145  		os.Exit(1)
   146  	}
   147  }