diff --git a/controllers/auth.go b/controllers/auth.go
index 5e171e4e..ffad4576 100644
--- a/controllers/auth.go
+++ b/controllers/auth.go
@@ -109,7 +109,7 @@ func (c *ApiController) GetApplicationLogin() {
}
func setHttpClient(idProvider idp.IdProvider, providerType string) {
- if providerType == "GitHub" || providerType == "Google" || providerType == "Facebook" || providerType == "LinkedIn" {
+ if providerType == "GitHub" || providerType == "Google" || providerType == "Facebook" || providerType == "LinkedIn" || providerType == "Steam" {
idProvider.SetHttpClient(proxy.ProxyHttpClient)
} else {
idProvider.SetHttpClient(proxy.DefaultHttpClient)
diff --git a/idp/goth.go b/idp/goth.go
index 825df42f..2b9fe5fb 100644
--- a/idp/goth.go
+++ b/idp/goth.go
@@ -45,6 +45,7 @@ import (
"github.com/markbates/goth/providers/salesforce"
"github.com/markbates/goth/providers/shopify"
"github.com/markbates/goth/providers/slack"
+ "github.com/markbates/goth/providers/steam"
"github.com/markbates/goth/providers/tumblr"
"github.com/markbates/goth/providers/twitter"
"github.com/markbates/goth/providers/yahoo"
@@ -171,6 +172,11 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: slack.New(clientId, clientSecret, redirectUrl),
Session: &slack.Session{},
}
+ case "Steam":
+ idp = GothIdProvider{
+ Provider: steam.New(clientSecret, redirectUrl),
+ Session: &steam.Session{},
+ }
case "Tumblr":
idp = GothIdProvider{
Provider: tumblr.New(clientId, clientSecret, redirectUrl),
@@ -209,10 +215,21 @@ func (idp *GothIdProvider) SetHttpClient(client *http.Client) {
func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
var expireAt time.Time
- //Need to construct variables supported by goth
- //to call the function to obtain accessToken
- value := url.Values{}
- value.Add("code", code)
+ var value url.Values
+ var err error
+ if idp.Provider.Name() == "steam" {
+ value, err = url.ParseQuery(code)
+ returnUrl := reflect.ValueOf(idp.Session).Elem().FieldByName("CallbackURL")
+ returnUrl.Set(reflect.ValueOf(value.Get("openid.return_to")))
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ //Need to construct variables supported by goth
+ //to call the function to obtain accessToken
+ value = url.Values{}
+ value.Add("code", code)
+ }
accessToken, err := idp.Session.Authorize(idp.Provider, value)
//Get ExpiresAt's value
valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt")
@@ -231,10 +248,10 @@ func (idp *GothIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
if err != nil {
return nil, err
}
- return getUser(gothUser), nil
+ return getUser(gothUser, idp.Provider.Name()), nil
}
-func getUser(gothUser goth.User) *UserInfo {
+func getUser(gothUser goth.User, provider string) *UserInfo {
user := UserInfo{
Id: gothUser.UserID,
Username: gothUser.Name,
@@ -258,7 +275,10 @@ func getUser(gothUser goth.User) *UserInfo {
user.DisplayName = user.Username
}
}
-
+ if provider == "steam" {
+ user.Username = user.DisplayName
+ user.Email = ""
+ }
return &user
}
diff --git a/idp/provider.go b/idp/provider.go
index a7015496..44582970 100644
--- a/idp/provider.go
+++ b/idp/provider.go
@@ -83,7 +83,7 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
return nil
}
-var gothList = []string{"Apple", "AzureAd", "Slack"}
+var gothList = []string{"Apple", "AzureAd", "Slack", "Steam"}
func isGothSupport(provider string) bool {
for _, value := range gothList {
diff --git a/object/user.go b/object/user.go
index 535b5cce..0d500dfe 100644
--- a/object/user.go
+++ b/object/user.go
@@ -84,6 +84,7 @@ type User struct {
Apple string `xorm:"apple varchar(100)" json:"apple"`
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
Slack string `xorm:"slack varchar(100)" json:"slack"`
+ Steam string `xorm:"steam varchar(100)" json:"steam"`
Ldap string `xorm:"ldap varchar(100)" json:"ldap"`
Properties map[string]string `json:"properties"`
diff --git a/web/src/Setting.js b/web/src/Setting.js
index 20a3313d..11fead41 100644
--- a/web/src/Setting.js
+++ b/web/src/Setting.js
@@ -403,6 +403,7 @@ export function getProviderTypeOptions(category) {
{id: 'Apple', name: 'Apple'},
{id: 'AzureAD', name: 'AzureAD'},
{id: 'Slack', name: 'Slack'},
+ {id: 'Steam', name: 'Steam'},
]
);
} else if (category === "Email") {
diff --git a/web/src/auth/AuthCallback.js b/web/src/auth/AuthCallback.js
index f57bfcb9..df146a8e 100644
--- a/web/src/auth/AuthCallback.js
+++ b/web/src/auth/AuthCallback.js
@@ -69,6 +69,7 @@ class AuthCallback extends React.Component {
UNSAFE_componentWillMount() {
const params = new URLSearchParams(this.props.location.search);
+ let isSteam = params.get("openid.mode")
let code = params.get("code");
// WeCom returns "auth_code=xxx" instead of "code=xxx"
if (code === null) {
@@ -78,6 +79,10 @@ class AuthCallback extends React.Component {
if (code === null) {
code = params.get("authCode")
}
+ //Steam don't use code, so we should use all params as code.
+ if (isSteam !== null && code === null) {
+ code = this.props.location.search
+ }
const innerParams = this.getInnerParams();
const applicationName = innerParams.get("application");
diff --git a/web/src/auth/LoginPage.js b/web/src/auth/LoginPage.js
index 22154503..c0c6ed30 100644
--- a/web/src/auth/LoginPage.js
+++ b/web/src/auth/LoginPage.js
@@ -39,6 +39,7 @@ import InfoflowLoginButton from "./InfoflowLoginButton";
import AppleLoginButton from "./AppleLoginButton"
import AzureADLoginButton from "./AzureADLoginButton";
import SlackLoginButton from "./SlackLoginButton";
+import SteamLoginButton from "./SteamLoginButton";
import CustomGithubCorner from "../CustomGithubCorner";
import {CountDownInput} from "../common/CountDownInput";
@@ -197,6 +198,8 @@ class LoginPage extends React.Component {
return
} else if (type === "Slack") {
return
+ } else if (type === "Steam") {
+ return
}
return text;
diff --git a/web/src/auth/Provider.js b/web/src/auth/Provider.js
index cec90af3..fde9e720 100644
--- a/web/src/auth/Provider.js
+++ b/web/src/auth/Provider.js
@@ -89,6 +89,9 @@ const authInfo = {
scope: "users:read",
endpoint: "https://slack.com/oauth/authorize",
},
+ Steam: {
+ endpoint: "https://steamcommunity.com/openid/login",
+ },
};
const otherProviderInfo = {
@@ -274,5 +277,7 @@ export function getAuthUrl(application, provider, method) {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&resource=https://graph.windows.net/`;
} else if (provider.type === "Slack") {
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
+ } else if (provider.type === "Steam") {
+ return `${endpoint}?openid.claimed_id=http://specs.openid.net/auth/2.0/identifier_select&openid.identity=http://specs.openid.net/auth/2.0/identifier_select&openid.mode=checkid_setup&openid.ns=http://specs.openid.net/auth/2.0&openid.realm=${window.location.origin}&openid.return_to=${redirectUri}?state=${state}`;
}
}
diff --git a/web/src/auth/SteamLoginButton.js b/web/src/auth/SteamLoginButton.js
new file mode 100644
index 00000000..2bbeb4f4
--- /dev/null
+++ b/web/src/auth/SteamLoginButton.js
@@ -0,0 +1,32 @@
+// Copyright 2022 The casbin Authors. All Rights Reserved.
+//
+// Licensed 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.
+
+import {createButton} from "react-social-login-buttons";
+import {StaticBaseUrl} from "../Setting";
+
+function Icon({ width = 24, height = 24, color }) {
+ return
;
+}
+
+const config = {
+ text: "Sign in with Steam",
+ icon: Icon,
+ iconFormat: name => `fa fa-${name}`,
+ style: {background: "#ffffff", color: "#000000"},
+ activeStyle: {background: "#ededee"},
+};
+
+const SteamLoginButton = createButton(config);
+
+export default SteamLoginButton;