github.com/versent/saml2aws@v2.17.0+incompatible/saml2aws.go (about)

     1  package saml2aws
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  
     7  	"github.com/versent/saml2aws/pkg/cfg"
     8  	"github.com/versent/saml2aws/pkg/creds"
     9  	"github.com/versent/saml2aws/pkg/provider/aad"
    10  	"github.com/versent/saml2aws/pkg/provider/adfs"
    11  	"github.com/versent/saml2aws/pkg/provider/adfs2"
    12  	"github.com/versent/saml2aws/pkg/provider/f5apm"
    13  	"github.com/versent/saml2aws/pkg/provider/googleapps"
    14  	"github.com/versent/saml2aws/pkg/provider/jumpcloud"
    15  	"github.com/versent/saml2aws/pkg/provider/keycloak"
    16  	"github.com/versent/saml2aws/pkg/provider/okta"
    17  	"github.com/versent/saml2aws/pkg/provider/onelogin"
    18  	"github.com/versent/saml2aws/pkg/provider/pingfed"
    19  	"github.com/versent/saml2aws/pkg/provider/pingone"
    20  	"github.com/versent/saml2aws/pkg/provider/psu"
    21  	"github.com/versent/saml2aws/pkg/provider/shibboleth"
    22  )
    23  
    24  // ProviderList list of providers with their MFAs
    25  type ProviderList map[string][]string
    26  
    27  // MFAsByProvider a list of providers with their respective supported MFAs
    28  var MFAsByProvider = ProviderList{
    29  	"AzureAD":    []string{"Auto", "PhoneAppOTP", "PhoneAppNotification", "OneWaySMS"},
    30  	"ADFS":       []string{"Auto", "VIP"},
    31  	"ADFS2":      []string{"Auto", "RSA"}, // nothing automatic about ADFS 2.x
    32  	"Ping":       []string{"Auto"},        // automatically detects PingID
    33  	"PingOne":    []string{"Auto"},        // automatically detects PingID
    34  	"JumpCloud":  []string{"Auto"},
    35  	"Okta":       []string{"Auto", "PUSH", "DUO", "SMS", "TOTP", "OKTA"}, // automatically detects DUO, SMS and ToTP
    36  	"OneLogin":   []string{"Auto", "OLP", "SMS", "TOTP"},                 // automatically detects OneLogin Protect, SMS and ToTP
    37  	"KeyCloak":   []string{"Auto"},                                       // automatically detects ToTP
    38  	"GoogleApps": []string{"Auto"},                                       // automatically detects ToTP
    39  	"Shibboleth": []string{"Auto"},
    40  	"PSU":        []string{"Auto"},
    41  	"F5APM":      []string{"Auto"},
    42  }
    43  
    44  // Names get a list of provider names
    45  func (mfbp ProviderList) Names() []string {
    46  	keys := []string{}
    47  	for k := range mfbp {
    48  		keys = append(keys, k)
    49  	}
    50  
    51  	sort.Strings(keys)
    52  
    53  	return keys
    54  }
    55  
    56  // Mfas retrieve a sorted list of mfas from the provider list
    57  func (mfbp ProviderList) Mfas(provider string) []string {
    58  	mfas := mfbp[provider]
    59  
    60  	sort.Strings(mfas)
    61  
    62  	return mfas
    63  }
    64  
    65  func (mfbp ProviderList) stringInSlice(a string, list []string) bool {
    66  	for _, b := range list {
    67  		if b == a {
    68  			return true
    69  		}
    70  	}
    71  	return false
    72  }
    73  
    74  func invalidMFA(provider string, mfa string) bool {
    75  	supportedMfas := MFAsByProvider.Mfas(provider)
    76  	return !MFAsByProvider.stringInSlice(mfa, supportedMfas)
    77  }
    78  
    79  // SAMLClient client interface
    80  type SAMLClient interface {
    81  	Authenticate(loginDetails *creds.LoginDetails) (string, error)
    82  }
    83  
    84  // NewSAMLClient create a new SAML client
    85  func NewSAMLClient(idpAccount *cfg.IDPAccount) (SAMLClient, error) {
    86  	switch idpAccount.Provider {
    87  	case "AzureAD":
    88  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
    89  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
    90  		}
    91  		return aad.New(idpAccount)
    92  	case "ADFS":
    93  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
    94  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
    95  		}
    96  		return adfs.New(idpAccount)
    97  	case "ADFS2":
    98  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
    99  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   100  		}
   101  		return adfs2.New(idpAccount)
   102  	case "Ping":
   103  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   104  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   105  		}
   106  		return pingfed.New(idpAccount)
   107  	case "PingOne":
   108  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   109  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   110  		}
   111  		return pingone.New(idpAccount)
   112  	case "JumpCloud":
   113  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   114  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   115  		}
   116  		return jumpcloud.New(idpAccount)
   117  	case "Okta":
   118  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   119  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   120  		}
   121  		return okta.New(idpAccount)
   122  	case "OneLogin":
   123  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   124  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   125  		}
   126  		return onelogin.New(idpAccount)
   127  	case "KeyCloak":
   128  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   129  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   130  		}
   131  		return keycloak.New(idpAccount)
   132  	case "GoogleApps":
   133  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   134  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   135  		}
   136  		return googleapps.New(idpAccount)
   137  	case "Shibboleth":
   138  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   139  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   140  		}
   141  		return shibboleth.New(idpAccount)
   142  	case "PSU":
   143  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   144  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   145  		}
   146  		return psu.New(idpAccount)
   147  	case "F5APM":
   148  		if invalidMFA(idpAccount.Provider, idpAccount.MFA) {
   149  			return nil, fmt.Errorf("Invalid MFA type: %v for %v provider", idpAccount.MFA, idpAccount.Provider)
   150  		}
   151  		return f5apm.New(idpAccount)
   152  
   153  	default:
   154  		return nil, fmt.Errorf("Invalid provider: %v", idpAccount.Provider)
   155  	}
   156  }