forked from filipg/gonito
Handle JWT tokens
This commit is contained in:
parent
a0577ba249
commit
ceef7ae5ac
@ -168,6 +168,9 @@ instance Yesod App where
|
||||
isAuthorized (ChallengeHowToR _) _ = regularAuthorization
|
||||
isAuthorized (ChallengeReadmeR _) _ = regularAuthorization
|
||||
isAuthorized (ChallengeAllSubmissionsR _) _ = regularAuthorization
|
||||
|
||||
isAuthorized (ChallengeMySubmissionsJsonR _) _ = regularAuthorization
|
||||
|
||||
isAuthorized (ChallengeGraphDataR _) _ = regularAuthorization
|
||||
isAuthorized (ChallengeDiscussionR _) _ = regularAuthorization
|
||||
isAuthorized (ChallengeDiscussionFeedR _) _ = regularAuthorization
|
||||
|
@ -20,6 +20,13 @@ import Handler.Dashboard
|
||||
import Handler.Common
|
||||
import Handler.Evaluate
|
||||
|
||||
import qualified Data.ByteString as BS
|
||||
import Data.Word8 (isSpace, toLower)
|
||||
import Network.Wai (Request, requestHeaders)
|
||||
import qualified Jose.Jwt as JWT
|
||||
import qualified Jose.Jwa as JWA
|
||||
import qualified Jose.Jwk as JWK
|
||||
|
||||
import Data.Maybe (fromJust)
|
||||
|
||||
import Text.Blaze
|
||||
@ -649,6 +656,23 @@ submissionForm defaultUrl defBranch defaultGitAnnexRemote = renderBootstrap3 Boo
|
||||
<*> areq textField (bfs MsgSubmissionBranch) defBranch
|
||||
<*> aopt textField (bfs MsgSubmissionGitAnnexRemote) (Just defaultGitAnnexRemote))
|
||||
|
||||
getChallengeMySubmissionsJsonR :: Text -> Handler Value
|
||||
getChallengeMySubmissionsJsonR name = do
|
||||
req <- waiRequest
|
||||
let mToken = case lookup "Authorization" (Network.Wai.requestHeaders req) of
|
||||
Nothing -> Nothing
|
||||
Just authHead -> case BS.break isSpace authHead of
|
||||
(strategy, token)
|
||||
| BS.map Data.Word8.toLower strategy == "bearer" -> (Just $ BS.filter (/= 32) token)
|
||||
| otherwise -> Nothing
|
||||
mUserEnt <- maybeAuth
|
||||
|
||||
app <- getYesod
|
||||
let jwk = fromJust $ appJSONWebKey $ appSettings app
|
||||
|
||||
dtoken <- liftIO $ JWT.decode [jwk] (Just (JWT.JwsEncoding JWA.RS256)) $ fromJust mToken
|
||||
return $ array [show dtoken]
|
||||
|
||||
getChallengeMySubmissionsR :: Text -> Handler Html
|
||||
getChallengeMySubmissionsR name = do
|
||||
userId <- requireAuthId
|
||||
|
@ -18,6 +18,9 @@ import Yesod.Default.Config2 (applyEnvValue, configSettingsYml)
|
||||
import Yesod.Default.Util (WidgetFileSettings, widgetFileNoReload,
|
||||
widgetFileReload)
|
||||
|
||||
import qualified Jose.Jwk as JWK
|
||||
import Data.Aeson
|
||||
|
||||
data RepoScheme = SelfHosted | Branches
|
||||
deriving (Eq, Show)
|
||||
|
||||
@ -92,6 +95,7 @@ data AppSettings = AppSettings
|
||||
, appServerSSHPublicKey :: Maybe Text
|
||||
-- ^ Are challenges, submission, etc. visible without logging in
|
||||
, appIsPublic :: Bool
|
||||
, appJSONWebKey :: Maybe JWK.Jwk
|
||||
}
|
||||
|
||||
instance FromJSON AppSettings where
|
||||
@ -137,6 +141,8 @@ instance FromJSON AppSettings where
|
||||
|
||||
appIsPublic <- o .:? "is-public" .!= False
|
||||
|
||||
appJSONWebKey <- o .:? "json-web-key"
|
||||
|
||||
return AppSettings {..}
|
||||
|
||||
-- | Settings for 'widgetFile', such as which template languages to support and
|
||||
|
@ -12,6 +12,7 @@
|
||||
/list-challenges ListChallengesR GET
|
||||
/api/list-challenges ListChallengesJsonR GET
|
||||
/api/leaderboard/#Text LeaderboardJsonR GET
|
||||
/api/challenge-my-submissions/#Text ChallengeMySubmissionsJsonR GET
|
||||
/list-archived-challenges ListArchivedChallengesR GET
|
||||
/challenge-image/#ChallengeId ChallengeImageR GET
|
||||
|
||||
|
@ -41,4 +41,25 @@ admin-user: "_env:ADMINUSER:"
|
||||
admin-password: "_env:ADMINPASS:"
|
||||
location: "_env:LOCATION:"
|
||||
|
||||
# If set, the key given, in the JWK format, will be used to verify and
|
||||
# trust JWT tokens sent by the client as Authorization/Bearer.
|
||||
# The JWT token will be checked first for a given request, if not provided
|
||||
# the standard auth procedure will used.
|
||||
#
|
||||
# If unset, the Authorization will NOT be checked at all (only the standard
|
||||
# auth procedure will be applied).
|
||||
#
|
||||
# A JWK key is something like:
|
||||
#
|
||||
# {"kty":"RSA", alg:"RS256", "use":"sig", "kid":"h01jmt_bD-1Di8i_GYbEV2a4NxhptzySHO-R8VuNHVA", "e":"AQAB", "n": "qG1elE6KPW3BYMxNpgK73MoksvbrUSfpRY4z9hU5iMsJREyD5Ar6XpjM1xAr6G7xglnOoumPC9o6FqhDHihm6QdJ5s5MA9ZyGkbi--kvy9Qc2d_VIGU-UR4vwyk3hAwXOFLhoknpQrJBJmMQvGFdas1Yr-m9EIWwT1zN7neHZkRUYZSVyQw_XghtMIWAUsLnhr6mM7nstHLafgxe5Qamzuc4K5EC_qipFXu4ugYkMDnaknlhkT43m7tcduVDnv5GV_4dBesF7FRII8tgUQWyw3Ty_FIoq43SInUPU_9cxA-qPGQz5C50th2aJl1z1snpLWS_1Zfsa8lnFsMj8_oh6w"}
|
||||
#
|
||||
# If you use Keycloak, it can be retrived via:
|
||||
#
|
||||
# https://<HOST>/auth/realms/<REALM>/protocol/openid-connect/certs
|
||||
#
|
||||
# (key/0 element).
|
||||
#
|
||||
# Note: at the moment, only RS256 is handled.
|
||||
json-web-key: "_env:JSON_WEB_KEY"
|
||||
|
||||
#analytics: UA-YOURCODE
|
||||
|
@ -152,6 +152,8 @@ library
|
||||
, Glob
|
||||
, req
|
||||
, wai-cors
|
||||
, word8
|
||||
, jose-jwt
|
||||
|
||||
executable gonito
|
||||
if flag(library-only)
|
||||
|
15
stack.yaml
15
stack.yaml
@ -4,5 +4,18 @@ flags:
|
||||
dev: false
|
||||
packages:
|
||||
- '.'
|
||||
extra-deps: [../geval,wai-handler-fastcgi-3.0.0.2,murmur3-1.0.3,random-strings-0.1.1.0,naturalcomp-0.0.3,Munkres-0.1,Chart-1.9.1,Chart-cairo-1.9.1,multiset-0.3.4.1,pwstore-fast-2.4.4,yesod-table-2.0.3,esqueleto-3.0.0,'ordered-containers-0.2.2@sha256:ebf2be3f592d9cf148ea6b8375f8af97148d44f82d8d04476899285e965afdbf,810']
|
||||
extra-deps:
|
||||
- ../geval
|
||||
- wai-handler-fastcgi-3.0.0.2
|
||||
- murmur3-1.0.3
|
||||
- random-strings-0.1.1.0
|
||||
- naturalcomp-0.0.3
|
||||
- Munkres-0.1
|
||||
- Chart-1.9.1
|
||||
- Chart-cairo-1.9.1
|
||||
- multiset-0.3.4.1
|
||||
- pwstore-fast-2.4.4
|
||||
- yesod-table-2.0.3
|
||||
- esqueleto-3.0.0
|
||||
- 'ordered-containers-0.2.2@sha256:ebf2be3f592d9cf148ea6b8375f8af97148d44f82d8d04476899285e965afdbf,810'
|
||||
resolver: lts-12.26
|
||||
|
1426
static/js/keycloak.js
Normal file
1426
static/js/keycloak.js
Normal file
File diff suppressed because it is too large
Load Diff
54
static/test-gonito-as-backend.html
Normal file
54
static/test-gonito-as-backend.html
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<script src="/static/js/keycloak.js"></script>
|
||||
<script>
|
||||
var keycloak;
|
||||
function initKeycloak() {
|
||||
keycloak = new Keycloak({
|
||||
url: 'http://127.0.0.1:8080/auth',
|
||||
realm: 'master',
|
||||
clientId: 'myapp',
|
||||
"enable-cors": true
|
||||
})
|
||||
keycloak.init({
|
||||
onLoad: 'login-required'
|
||||
}).then(function(authenticated) {
|
||||
// alert(authenticated ? 'authenticated' : 'not authenticated');
|
||||
}).catch(function() {
|
||||
alert('failed to initialize');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
var loadData = function () {
|
||||
|
||||
var url = 'http://127.0.0.1:3000/api/challenge-my-submissions/retroc2';
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('GET', url, true);
|
||||
req.setRequestHeader('Accept', 'application/json');
|
||||
req.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);
|
||||
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState == 4) {
|
||||
if (req.status == 200) {
|
||||
alert(req.response);
|
||||
} else if (req.status == 403) {
|
||||
alert('Forbidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req.send();
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="initKeycloak()">
|
||||
<h1>This is a simple web page to test Gonito as a backend with authorization by JWT tokens.</h1>
|
||||
|
||||
<p><button onclick="loadData()">Test</button></p>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user