mirror of https://github.com/portainer/portainer
feat(setting/oauth): add authstyle option [EE-6038] (#11590)
parent
a755e6be15
commit
ccfd5e4500
|
@ -631,6 +631,7 @@
|
|||
"LogoURL": "",
|
||||
"OAuthSettings": {
|
||||
"AccessTokenURI": "",
|
||||
"AuthStyle": 0,
|
||||
"AuthorizationURI": "",
|
||||
"ClientID": "",
|
||||
"DefaultTeamID": 0,
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||
"github.com/portainer/portainer/pkg/libhttp/request"
|
||||
"github.com/portainer/portainer/pkg/libhttp/response"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -95,6 +96,9 @@ func (payload *settingsUpdatePayload) Validate(r *http.Request) error {
|
|||
}
|
||||
}
|
||||
|
||||
if payload.OAuthSettings.AuthStyle < oauth2.AuthStyleAutoDetect || payload.OAuthSettings.AuthStyle > oauth2.AuthStyleInHeader {
|
||||
return errors.New("Invalid OAuth AuthStyle")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -225,6 +229,7 @@ func (handler *Handler) updateSettings(tx dataservices.DataStoreTx, payload sett
|
|||
settings.OAuthSettings = *payload.OAuthSettings
|
||||
settings.OAuthSettings.ClientSecret = clientSecret
|
||||
settings.OAuthSettings.KubeSecretKey = kubeSecret
|
||||
settings.OAuthSettings.AuthStyle = payload.OAuthSettings.AuthStyle
|
||||
}
|
||||
|
||||
if payload.EnableEdgeComputeFeatures != nil {
|
||||
|
|
|
@ -172,8 +172,9 @@ func getResource(token string, configuration *portainer.OAuthSettings) (map[stri
|
|||
|
||||
func buildConfig(configuration *portainer.OAuthSettings) *oauth2.Config {
|
||||
endpoint := oauth2.Endpoint{
|
||||
AuthURL: configuration.AuthorizationURI,
|
||||
TokenURL: configuration.AccessTokenURI,
|
||||
AuthURL: configuration.AuthorizationURI,
|
||||
TokenURL: configuration.AccessTokenURI,
|
||||
AuthStyle: configuration.AuthStyle,
|
||||
}
|
||||
|
||||
return &oauth2.Config{
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
gittypes "github.com/portainer/portainer/api/git/types"
|
||||
models "github.com/portainer/portainer/api/http/models/kubernetes"
|
||||
"github.com/portainer/portainer/pkg/featureflags"
|
||||
"golang.org/x/oauth2"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
|
@ -758,19 +759,20 @@ type (
|
|||
|
||||
// OAuthSettings represents the settings used to authorize with an authorization server
|
||||
OAuthSettings struct {
|
||||
ClientID string `json:"ClientID"`
|
||||
ClientSecret string `json:"ClientSecret,omitempty"`
|
||||
AccessTokenURI string `json:"AccessTokenURI"`
|
||||
AuthorizationURI string `json:"AuthorizationURI"`
|
||||
ResourceURI string `json:"ResourceURI"`
|
||||
RedirectURI string `json:"RedirectURI"`
|
||||
UserIdentifier string `json:"UserIdentifier"`
|
||||
Scopes string `json:"Scopes"`
|
||||
OAuthAutoCreateUsers bool `json:"OAuthAutoCreateUsers"`
|
||||
DefaultTeamID TeamID `json:"DefaultTeamID"`
|
||||
SSO bool `json:"SSO"`
|
||||
LogoutURI string `json:"LogoutURI"`
|
||||
KubeSecretKey []byte `json:"KubeSecretKey"`
|
||||
ClientID string `json:"ClientID"`
|
||||
ClientSecret string `json:"ClientSecret,omitempty"`
|
||||
AccessTokenURI string `json:"AccessTokenURI"`
|
||||
AuthorizationURI string `json:"AuthorizationURI"`
|
||||
ResourceURI string `json:"ResourceURI"`
|
||||
RedirectURI string `json:"RedirectURI"`
|
||||
UserIdentifier string `json:"UserIdentifier"`
|
||||
Scopes string `json:"Scopes"`
|
||||
OAuthAutoCreateUsers bool `json:"OAuthAutoCreateUsers"`
|
||||
DefaultTeamID TeamID `json:"DefaultTeamID"`
|
||||
SSO bool `json:"SSO"`
|
||||
LogoutURI string `json:"LogoutURI"`
|
||||
KubeSecretKey []byte `json:"KubeSecretKey"`
|
||||
AuthStyle oauth2.AuthStyle `json:"AuthStyle"`
|
||||
}
|
||||
|
||||
// Pair defines a key/value string pair
|
||||
|
|
|
@ -78,6 +78,7 @@ export function OAuthSettingsViewModel(data) {
|
|||
this.DefaultTeamID = data.DefaultTeamID;
|
||||
this.SSO = data.SSO;
|
||||
this.LogoutURI = data.LogoutURI;
|
||||
this.AuthStyle = data.AuthStyle;
|
||||
}
|
||||
|
||||
export function EdgeSettingsViewModel(data = {}) {
|
||||
|
|
|
@ -4,7 +4,6 @@ import { isLimitedToBE } from '@/react/portainer/feature-flags/feature-flags.ser
|
|||
import { ModalType } from '@@/modals';
|
||||
import { confirm } from '@@/modals/confirm';
|
||||
import { buildConfirmButton } from '@@/modals/utils';
|
||||
|
||||
import providers, { getProviderByUrl } from './providers';
|
||||
|
||||
const MS_TENANT_ID_PLACEHOLDER = 'TENANT_ID';
|
||||
|
@ -31,6 +30,7 @@ export default class OAuthSettingsController {
|
|||
this.addTeamMembershipMapping = this.addTeamMembershipMapping.bind(this);
|
||||
this.removeTeamMembership = this.removeTeamMembership.bind(this);
|
||||
this.onToggleAutoTeamMembership = this.onToggleAutoTeamMembership.bind(this);
|
||||
this.onChangeAuthStyle = this.onChangeAuthStyle.bind(this);
|
||||
}
|
||||
|
||||
onMicrosoftTenantIDChange() {
|
||||
|
@ -54,6 +54,7 @@ export default class OAuthSettingsController {
|
|||
this.settings.LogoutURI = provider.logoutUrl;
|
||||
this.settings.UserIdentifier = provider.userIdentifier;
|
||||
this.settings.Scopes = provider.scopes;
|
||||
this.settings.AuthStyle = provider.authStyle;
|
||||
|
||||
if (providerId === 'microsoft' && this.state.microsoftTenantID !== '') {
|
||||
this.onMicrosoftTenantIDChange();
|
||||
|
@ -77,6 +78,12 @@ export default class OAuthSettingsController {
|
|||
});
|
||||
}
|
||||
|
||||
onChangeAuthStyle(val) {
|
||||
this.$scope.$evalAsync(() => {
|
||||
this.settings.AuthStyle = val;
|
||||
});
|
||||
}
|
||||
|
||||
async onChangeHideInternalAuth(checked) {
|
||||
this.$async(async () => {
|
||||
if (this.isLimitedToBE) {
|
||||
|
|
|
@ -341,6 +341,8 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<oauth-auth-style value="$ctrl.settings.AuthStyle" on-change="($ctrl.onChangeAuthStyle)"></oauth-auth-style>
|
||||
<save-auth-settings-button
|
||||
on-save-settings="($ctrl.onSaveSettings)"
|
||||
save-button-state="($ctrl.saveButtonState)"
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { baseHref } from '@/portainer/helpers/pathHelper';
|
||||
import { OAuthStyle } from '@/react/portainer/settings/types';
|
||||
|
||||
export default {
|
||||
microsoft: {
|
||||
|
@ -8,6 +9,7 @@ export default {
|
|||
logoutUrl: `https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/logout`,
|
||||
userIdentifier: 'userPrincipalName',
|
||||
scopes: 'profile openid',
|
||||
authStyle: OAuthStyle.InParams,
|
||||
},
|
||||
google: {
|
||||
authUrl: 'https://accounts.google.com/o/oauth2/auth',
|
||||
|
@ -16,6 +18,7 @@ export default {
|
|||
logoutUrl: `https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=${window.location.origin}${baseHref()}#!/auth`,
|
||||
userIdentifier: 'email',
|
||||
scopes: 'profile email',
|
||||
authStyle: OAuthStyle.InParams,
|
||||
},
|
||||
github: {
|
||||
authUrl: 'https://github.com/login/oauth/authorize',
|
||||
|
@ -24,8 +27,9 @@ export default {
|
|||
logoutUrl: `https://github.com/logout`,
|
||||
userIdentifier: 'login',
|
||||
scopes: 'id email name',
|
||||
authStyle: OAuthStyle.AutoDetect,
|
||||
},
|
||||
custom: { authUrl: '', accessTokenUrl: '', resourceUrl: '', logoutUrl: '', userIdentifier: '', scopes: '' },
|
||||
custom: { authUrl: '', accessTokenUrl: '', resourceUrl: '', logoutUrl: '', userIdentifier: '', scopes: '', authStyle: OAuthStyle.AutoDetect },
|
||||
};
|
||||
|
||||
export function getProviderByUrl(providerAuthURL = '') {
|
||||
|
|
|
@ -11,6 +11,7 @@ import { KubeSettingsPanel } from '@/react/portainer/settings/SettingsView/KubeS
|
|||
import { HelmCertPanel } from '@/react/portainer/settings/SettingsView/HelmCertPanel';
|
||||
import { HiddenContainersPanel } from '@/react/portainer/settings/SettingsView/HiddenContainersPanel/HiddenContainersPanel';
|
||||
import { SSLSettingsPanelWrapper } from '@/react/portainer/settings/SettingsView/SSLSettingsPanel/SSLSettingsPanel';
|
||||
import { AuthStyleField } from '@/react/portainer/settings/AuthenticationView/OAuth';
|
||||
|
||||
export const settingsModule = angular
|
||||
.module('portainer.app.react.components.settings', [])
|
||||
|
@ -39,4 +40,15 @@ export const settingsModule = angular
|
|||
.component(
|
||||
'kubeSettingsPanel',
|
||||
r2a(withUIRouter(withReactQuery(KubeSettingsPanel)), ['settings'])
|
||||
)
|
||||
.component(
|
||||
'oauthAuthStyle',
|
||||
r2a(AuthStyleField, [
|
||||
'value',
|
||||
'onChange',
|
||||
'label',
|
||||
'tooltip',
|
||||
'readonly',
|
||||
'size',
|
||||
])
|
||||
).name;
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { Options } from '@/react/edge/components/useIntervalOptions';
|
||||
import { OAuthStyle } from '@/react/portainer/settings/types';
|
||||
|
||||
import { FormControl, Size } from '@@/form-components/FormControl';
|
||||
import { Select } from '@@/form-components/Input';
|
||||
|
||||
interface Props {
|
||||
value: OAuthStyle;
|
||||
onChange(value: OAuthStyle): void;
|
||||
label?: string;
|
||||
tooltip?: string;
|
||||
readonly?: boolean;
|
||||
size?: Size;
|
||||
}
|
||||
|
||||
// The options are based on oauth2 lib definition @https://pkg.go.dev/golang.org/x/oauth2#AuthStyle
|
||||
export const authStyleOptions: Options = [
|
||||
{ label: 'Auto Detect', value: OAuthStyle.AutoDetect, isDefault: true },
|
||||
{ label: 'In Params', value: OAuthStyle.InParams },
|
||||
{ label: 'In Header', value: OAuthStyle.InHeader },
|
||||
];
|
||||
|
||||
export function AuthStyleField({
|
||||
value,
|
||||
readonly = false,
|
||||
onChange,
|
||||
label = 'Auth Style',
|
||||
tooltip = 'Auth Style specifies how the endpoint wants the client ID & client secret sent.',
|
||||
size = 'small',
|
||||
}: Props) {
|
||||
return (
|
||||
<FormControl
|
||||
inputId="oauth_authstyle"
|
||||
label={label}
|
||||
tooltip={tooltip}
|
||||
size={size}
|
||||
>
|
||||
<Select
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
onChange(parseInt(e.currentTarget.value, 10));
|
||||
}}
|
||||
options={authStyleOptions}
|
||||
disabled={readonly}
|
||||
id="oauth_authstyle"
|
||||
/>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export { AuthStyleField } from './AuthStyleField';
|
|
@ -87,6 +87,15 @@ export enum AuthenticationMethod {
|
|||
OAuth,
|
||||
}
|
||||
|
||||
/**
|
||||
* The definition are based on oauth2 lib definition @https://pkg.go.dev/golang.org/x/oauth2#AuthStyle
|
||||
*/
|
||||
export enum OAuthStyle {
|
||||
AutoDetect = 0,
|
||||
InParams,
|
||||
InHeader,
|
||||
}
|
||||
|
||||
type Feature = string;
|
||||
|
||||
export interface DefaultRegistry {
|
||||
|
|
Loading…
Reference in New Issue