Support for multiple oidc providers

This commit is contained in:
Pablo Terradillos 2016-11-15 20:46:40 -03:00
parent d355766e74
commit 638de1e251
10 changed files with 51 additions and 29 deletions

View file

@ -578,12 +578,18 @@ type OIDCConnector struct {
// client's browser back to it after successfull authentication
// Should match the URL on Provider's side
RedirectURL string `yaml:"redirect_url"`
Display string `yaml:"display"`
}
// Parse parses config struct into services connector and checks if it's valid
func (o *OIDCConnector) Parse() (*services.OIDCConnector, error) {
if o.Display == "" {
o.Display = o.ID
}
other := &services.OIDCConnector{
ID: o.ID,
Display: o.Display,
IssuerURL: o.IssuerURL,
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,

View file

@ -257,7 +257,7 @@ type SignupToken struct {
Expires time.Time `json:"expires"`
}
// OIDCConnector specifies configuration fo Open ID Connect compatible external
// OIDCConnector specifies configuration for Open ID Connect compatible external
// identity provider, e.g. google in some organisation
type OIDCConnector struct {
// ID is a provider id, 'e.g.' google, used internally
@ -273,6 +273,8 @@ type OIDCConnector struct {
// client's browser back to it after successfull authentication
// Should match the URL on Provider's side
RedirectURL string `json:"redirect_url"`
// Display - Friendly name for this provider.
Display string `json:"display"`
}
// Check returns nil if all parameters are great, err otherwise

View file

@ -238,9 +238,14 @@ func (m *Handler) Close() error {
return m.auth.Close()
}
type oidcConnector struct {
ID string `json:"id"`
Display string `json:"display"`
}
type webSettings struct {
Auth struct {
OIDCConnectors []string `json:"oidc_connectors"`
OIDCConnectors []oidcConnector `json:"oidc_connectors"`
} `json:"auth"`
}
@ -250,11 +255,17 @@ func (m *Handler) getSettings(w http.ResponseWriter, r *http.Request) (interface
if err != nil {
return nil, trace.Wrap(err)
}
for _, connector := range connectors {
settings.Auth.OIDCConnectors = append(settings.Auth.OIDCConnectors, connector.ID)
fmt.Printf("%v\n", connectors)
settings.Auth.OIDCConnectors = append(settings.Auth.OIDCConnectors, oidcConnector{
ID: connector.ID,
Display: connector.Display,
})
}
if len(settings.Auth.OIDCConnectors) == 0 {
settings.Auth.OIDCConnectors = make([]string, 0)
settings.Auth.OIDCConnectors = make([]oidcConnector, 0)
}
out, err := json.Marshal(settings)
if err != nil {

View file

@ -2457,9 +2457,6 @@ webpackJsonp([0],{
var _require2 = __webpack_require__(339),
TeleportLogo = _require2.TeleportLogo;
var _require3 = __webpack_require__(227),
PROVIDER_GOOGLE = _require3.PROVIDER_GOOGLE;
var LoginInputForm = React.createClass({
displayName: 'LoginInputForm',
@ -2482,10 +2479,13 @@ webpackJsonp([0],{
},
onLoginWithGoogle: function onLoginWithGoogle(e) {
e.preventDefault();
this.state.provider = PROVIDER_GOOGLE;
this.props.onClick(this.state);
providerLogin: function providerLogin(provider) {
var self = this;
return function (e) {
e.preventDefault();
self.state.provider = provider.id;
self.props.onClick(self.state);
};
},
isValid: function isValid() {
@ -2494,13 +2494,14 @@ webpackJsonp([0],{
},
render: function render() {
var _this = this;
var _props$attemp = this.props.attemp,
isProcessing = _props$attemp.isProcessing,
isFailed = _props$attemp.isFailed,
message = _props$attemp.message;
var providers = cfg.getAuthProviders();
var useGoogle = providers.indexOf(PROVIDER_GOOGLE) !== -1;
return React.createElement(
'form',
@ -2533,11 +2534,14 @@ webpackJsonp([0],{
{ onClick: this.onLogin, disabled: isProcessing, type: 'submit', className: 'btn btn-primary block full-width m-b' },
'Login'
),
useGoogle ? React.createElement(
'button',
{ onClick: this.onLoginWithGoogle, type: 'submit', className: 'btn btn-danger block full-width m-b' },
'With Google'
) : null,
providers.map(function (provider) {
return React.createElement(
'button',
{ onClick: _this.providerLogin(provider), type: 'submit', className: 'btn btn-danger block full-width m-b' },
'With ',
provider.display
);
}),
isFailed ? React.createElement(
'label',
{ className: 'error' },

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
web/dist/index.html vendored
View file

@ -10,5 +10,5 @@
<body class="grv">
<div id="app"></div>
<div id="bearer_token" style="display: none;">{{.Session}}</div>
<script type="text/javascript" src="/web/app/vendor.4bec98c1fb2c71cdb568.js"></script><script type="text/javascript" src="/web/app/styles.4bec98c1fb2c71cdb568.js"></script><script type="text/javascript" src="/web/app/app.4bec98c1fb2c71cdb568.js"></script></body>
<script type="text/javascript" src="/web/app/vendor.fe9ded10330844d319b3.js"></script><script type="text/javascript" src="/web/app/styles.fe9ded10330844d319b3.js"></script><script type="text/javascript" src="/web/app/app.fe9ded10330844d319b3.js"></script></body>
</html>

View file

@ -22,7 +22,6 @@ var {actions, getters} = require('app/modules/user');
var GoogleAuthInfo = require('./googleAuthLogo');
var cfg = require('app/config');
var {TeleportLogo} = require('./icons.jsx');
var {PROVIDER_GOOGLE} = require('app/services/auth');
var LoginInputForm = React.createClass({
@ -45,10 +44,13 @@ var LoginInputForm = React.createClass({
}
},
onLoginWithGoogle: function(e) {
e.preventDefault();
this.state.provider = PROVIDER_GOOGLE;
this.props.onClick(this.state);
providerLogin: function (provider) {
var self = this;
return function (e) {
e.preventDefault();
self.state.provider = provider.id;
self.props.onClick(self.state);
}
},
isValid: function() {
@ -59,7 +61,6 @@ var LoginInputForm = React.createClass({
render() {
let {isProcessing, isFailed, message } = this.props.attemp;
let providers = cfg.getAuthProviders();
let useGoogle = providers.indexOf(PROVIDER_GOOGLE) !== -1;
return (
<form ref="form" className="grv-login-input-form">
@ -75,7 +76,7 @@ var LoginInputForm = React.createClass({
<input autoComplete="off" valueLink={this.linkState('token')} className="form-control required" name="token" placeholder="Two factor token (Google Authenticator)"/>
</div>
<button onClick={this.onLogin} disabled={isProcessing} type="submit" className="btn btn-primary block full-width m-b">Login</button>
{ useGoogle ? <button onClick={this.onLoginWithGoogle} type="submit" className="btn btn-danger block full-width m-b">With Google</button> : null }
{ providers.map((provider) => <button onClick={this.providerLogin(provider)} type="submit" className="btn btn-danger block full-width m-b">With {provider.display}</button>) }
{ isFailed ? (<label className="error">{message}</label>) : null }
</div>
</form>

View file

@ -92,8 +92,6 @@ let cfg = {
var hostname = getWsHostName();
return `${hostname}/v1/webapi/sites/-current-`;
}
},
getFullUrl(url){