このリポジトリには、Cocodaマッピングツールで使用するログインサーバーが提供されます。ユーザーは、さまざまなプロバイダー(Github、Orcidなど)を使用して認証することができます。これをどのように使用できるかについては、https://coli-conc.gbv.de/login/apiを参照してください。
.envproviders.jsonapplications.jsonLogin-Serverには、node.js(> = v18、v20推奨)とmongodbデータベースへのアクセス(> = v5、v7推奨)が必要です。
git clone https://github.com/gbv/login-server.git
cd login-server
npm install
# after setting up or changing providers, create indexes
npm run indexesLogin-ServerはDockerからも利用できます。詳細については、https://github.com/gbv/login-server/blob/master/docker/readme.mdのドキュメントを参照してください。
逆プロキシの後ろにサーバーを実行している場合は、 X-Forwarded-Protoヘッダーを含め、すべてのHTTPメソッドを許可し、WebSocketプロキシを有効にしてください。
2つの構成ファイルを提供する必要があります。
.envアプリケーションを構成するには:
# recommended, port for express, default: 3004
PORT=
# recommended, full base URL, default: http://localhost[:PORT]/
# (required when used in production or behind a reverse proxy)
BASE_URL=
# title of application (will be shown in header)
TITLE=My Login Server
# list of allowed origins separated by comma, includes the hostname of BASE_URL by default
ALLOWED_ORIGINS=
# required for some strategies to enable production mode, default: development
NODE_ENV=production
# strongly recommended, imprint and privacy URLs for footer and clients
IMPRINT_URL=
PRIVACY_URL=
# recommended, secret used by the session
SESSION_SECRET=
# optional, maximum number of days a session is valid (rolling), default: 30
COOKIE_MAX_DAYS=
# threshold in minutes when to send "sessionAboutToExpire" events, default: 60
SESSION_EXPIRATION_MESSAGE_THRESHOLD=
# interval in minutes in which to check for expiring sessions, default: 5
SESSION_EXPIRATION_MESSAGE_INTERVAL=
# username used for MongoDB, default: <empty>
MONGO_USER=
# password used for MongoDB, default: <empty>
MONGO_PASS=
# host used for MongoDB, default: 127.0.0.1
MONGO_HOST=
# port used for MongoDB, default: 27017
MONGO_PORT=
# database used for MongoDB, default: login-server
MONGO_DB=
# the rate limit window in ms, default: 60 * 1000
RATE_LIMIT_WINDOW=
# the rate limit tries, default: 10
RATE_LIMIT_MAX=
# a jsonwebtoken compatible keypair
JWT_PRIVATE_KEY_PATH=
JWT_PUBLIC_KEY_PATH=
# the jsonwebtoken algorithm used
JWT_ALGORITHM=
# expiration time of JWTs in seconds, default: 120, min: 10
JWT_EXPIRES_IN=
# URL for Sources, default: https://github.com/gbv/login-server
SOURCES_URL=
# the path to the providers.json file, default: ./providers.json
PROVIDERS_PATH=
# log = log all messages, warn = only log warnings and errors, error = only log errorsl default: log
VERBOSITY=providers.jsonプロバイダーを構成します。プロバイダーを参照してください。
applications.jsonどのアプリケーションがデータにアクセスしているか、どのアプリケーションがセッションのログインを開始したかについての情報をユーザーに提供するには、 applications.jsonでアプリケーションのリストを提供できます。リストは一連のオブジェクトである必要があり、各オブジェクトにはurlとnameが必要です。例:
[
{
"url" : " https://bartoc.org " ,
"name" : " BARTOC "
},
{
"url" : " https://coli-conc.gbv.de/coli-rich/ " ,
"name" : " coli-rich "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/app/ " ,
"name" : " Cocoda "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/dev/ " ,
"name" : " Cocoda (dev) "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/rvk/ " ,
"name" : " Cocoda (RVK) "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/wikidata/ " ,
"name" : " Cocoda (Wikidata) "
},
{
"url" : " https://coli-conc.gbv.de/cocoda/ " ,
"name" : " Cocoda (other) "
},
{
"url" : " https://coli-conc.gbv.de " ,
"name" : " Other coli-conc application "
}
]インターフェイスがリンクするため、URLにアクセスできるはずです。リファラーURLにアプリケーションのurlが含まれている場合、セッションはアプリケーションに関連付けられています。アプリケーションは上から下にチェックされるため、最も特定のURLから最も特定のURLに注文する必要があります(上記の例を参照)。
npm run startサーバーは、Webインターフェイス、HTTP API、およびWebSocketを提供します。
Webインターフェイスにより、ユーザーはIDプロバイダーで複数のIDに接続してアカウントを作成および管理できます(プロバイダーを参照)。ログインサーバーはパスワード(シングルサインオン)を保存しないため、プロバイダーはユーザーを認証するために使用されます。
HTTP APIとWebSocketは、クライアントアプリケーションがログインサーバーと対話できるようにします。たとえば、ユーザーがログインしているかどうかを確認し、ユーザーに属するアイデンティティを確認します(JavaScriptライブラリのログインクライアントとログインクライアント-Vueを参照して、Webアプリケーションをログインサーバーに接続します)。
ログインサーバーをさらに使用して、ユーザーが他のサービスに対してユーザーを認証できるため、ユーザーはアイデンティティを証明できます。
ディレクトリbin 、ユーザーアカウントのリストやローカルプロバイダーの管理など、サーバーインスタンスを管理するためのヘルパースクリプトが含まれています。
テストでは、データベース名の後にPostfix -testを使用して、 .envで構成されたMONGODBを使用します。
npm test Login-Serverは、認証ミドルウェアとしてPassport(GitHub)を使用します。 Passportは、いわゆる「戦略」を使用して、さまざまなプロバイダーとの認証をサポートします。利用可能な戦略のリストはここにあります。現在、ログインサーバーでサポートされている戦略は次のとおりです。
戦略は検証コールバックで異なるパラメーターを使用するため、各戦略にはフォルダーstrategies/に独自のラッパーファイルがあります。ログインサーバーに別の戦略を追加するには、 {name}.js (ここで{name}というファイルを追加します{name}は、次の構造(例としてgithub)を持つpassport.authenticateで使用される戦略の名前です。
/**
* OAuth Stategy for GitHub.
*/
// Import strategy here
import { Strategy } from "passport-github"
// Don't change this part!
export default ( options , provider , callback ) => new Strategy ( options ,
// Strategies have different callback parameters.
// `req` is always the first and the `done` callback is always last.
( req , token , tokenSecret , profile , done ) => {
// Prepare a standardized object for the user profile,
// usually using information from the `profile` parameter
let providerProfile = {
// Required, don't change this!
provider : provider . id ,
// Required: Choose a field that represents a unique user ID for this user
id : profile . id ,
// Optional: Provides a display name (e.g. full name)
name : profile . displayName ,
// Optional: Provides a username
username : profile . username
}
// Call a custom callback. `req`, `providerProfile`, and `done` are required,
// `token` and `tokenSecret` can be null.
callback ( req , token , tokenSecret , providerProfile , done )
} )既存の戦略を例として見て、プルリクエストで独自の戦略を追加できます。
戦略を追加した後、プロバイダーをproviders.jsonに追加することで使用できます。JSON:
[
{
"id" : " github " ,
"strategy" : " github " ,
"name" : " GitHub " ,
"template" : " https://github.com/{username} " ,
"options" : {
"clientID" : " abcdef1234567890 " ,
"clientSecret" : " abcdef1234567890abcdef1234567890 "
},
"image" : " https://upload.wikimedia.org/wikipedia/commons/9/91/Octicons-mark-github.svg " ,
"url" : " https://github.com "
}
]プロバイダーのリスト内の各オブジェクトには、次のプロパティを持つことができます。
id (必須) - プロバイダー用の一意のID。strategy (必須) - プロバイダーが使用するパスポート戦略の名前。name (必須) - プロバイダーの名前を表示します。template (オプション) - URIを生成するテンプレート文字列(プレースホルダー{field}は、 providerProfileオブジェクト、通常は{id}または{username} )に提供される任意のフィールドにすることができます)。credentialsNecessary (オプション) - このプロバイダーにはユーザー名とパスワードの資格情報が必要な場合はtrueに設定されます。リダイレクトの代わりに(OAUTH用)、ログインサーバーには、資格情報をポストエンドポイントに送信するログインフォームが表示されます。options (ほとんど必須) - しばしば認証エンドポイントのクライアント資格情報を含む戦略のオプションオブジェクト。image (オプション) - プロバイダーに関連付けられた画像。ログインページと接続されたアイデンティティのリストに表示されます。フォルダーstatic/に静的画像を提供できます。プロパティの値は、 static/myimage.svgになります。ファイル名がプロバイダーのidと一致する場合、画像は自動的に関連付けられます。url (オプション) - プロバイダー用のURL。 /accountの下の画像 /アイコンにリンクされます。 github 、 orcid 、 mediawiki 、およびstackexchange戦略にはデフォルトのURLがあります。以下は、既存の各プロバイダーを構成する方法を示すproviders.json例です。
[
{
"id" : " github " ,
"strategy" : " github " ,
"name" : " GitHub " ,
"template" : " https://github.com/{username} " ,
"options" : {
"clientID" : " abcdef1234567890 " ,
"clientSecret" : " abcdef1234567890abcdef1234567890 "
}
},
{
"id" : " orcid " ,
"strategy" : " orcid " ,
"name" : " ORCID " ,
"template" : " https://orcid.org/{id} " ,
"options" : {
"clientID" : " APP-abcdef1234567890 " ,
"clientSecret" : " abcdef1-23456-7890ab-cdef12-34567890 "
}
},
{
"id" : " mediawiki " ,
"strategy" : " mediawiki " ,
"name" : " Mediawiki " ,
"template" : " https://www.mediawiki.org/wiki/User:{username} " ,
"options" : {
"consumerKey" : " abcdef1234567890 " ,
"consumerSecret" : " abcdef1234567890abcdef1234567890 "
}
},
{
"id" : " stackexchange " ,
"strategy" : " stackexchange " ,
"name" : " Stack Exchange " ,
"template" : " https://stackexchange.com/users/{id} " ,
"options" : {
"clientID" : " 12345 " ,
"clientSecret" : " abcdef1234567890(( " ,
"stackAppsKey" : " 1234567890abcdefg(( "
}
},
{
"id" : " my-ldap " ,
"strategy" : " ldapauth " ,
"name" : " My LDAP " ,
"credentialsNecessary" : true ,
"options" : {
"server" : {
"url" : " ldap://ldap.example.com " ,
"bindDN" : " uid=admin,dc=example,dc=com " ,
"bindCredentials" : " abcdef1234567890 " ,
"searchBase" : " dc=example,dc=com " ,
"searchFilter" : " (uid={{username}}) "
}
}
},
{
"id" : " easydb " ,
"name" : " easydb test provider " ,
"strategy" : " easydb " ,
"credentialsNecessary" : true ,
"options" : {
"url" : " https://easydb5-test.example.com/api/v1/ "
}
},
{
"id" : " some-script " ,
"strategy" : " script " ,
"name" : " Some Script " ,
"credentialsNecessary" : true ,
"template" : " https://example.org/some-script/{id} " ,
"options" : {
"script" : " ./bin/example-script "
}
},
{
"id" : " cbs " ,
"strategy" : " cbs " ,
"name" : " CBS " ,
"credentialsNecessary" : true ,
"template" : " cbs:{id} " ,
"options" : {
"url" : " https://example.com/ext/api/colirich/users/info " ,
"apiKey" : " abcdef1234567890 "
}
}
]ローカルプロバイダーを構成するには、 bin/manage-local.jsの下で提供されたスクリプトを使用してください。ローカルプロバイダーを作成/削除し、ローカルプロバイダーのユーザーを作成/削除できます。
PROVIDERS_PATH in .envを使用して、 providers.jsonファイルへのパスを調整できます。
Mediawikiプロバイダーの使用に関するメモ:
"baseURL": "https://www.wikidata.org/"など、そのインスタンスにそのインスタンスにbaseurlを提供する必要があります。https://coli-conc.gbv.de/login/login/wikidata/return )。スクリプトプロバイダーの使用に関するメモ:
lib/script-strategy.jsを参照)。options.scriptで提供)は、ログインサーバーのルートフォルダーに関連するか、絶対パス(Dockerに推奨されています)のいずれかです。bin/example-scriptに記載されています。chmod +x )。id値が設定されている有効なJSONを返す必要があります。オプションで、 nameを提供でき、ディスプレイ名として使用できます。Login-Serverは、JSON Webトークンを提供し、他のサービス(JSKOS-Serverなど)に対して認証するために使用できます。 JsonWebtokenは、トークンに署名するために使用されます。
デフォルトでは、アプリケーションが最初に開始されたときに新しいRSAキーペアが生成されます(ノードRSAを使用して2048ビット)。この生成されたKeypairは、デフォルトで./private.keyおよび./public.keyで利用可能になります。トークンを検証する必要がある他のサービスに./public.keyファイルを提供できます。あるいは、現在使用されている公開キーは、 /arboutエンドポイントで提供されます。
また、 JWT_PRIVATE_KEY_PATHおよびJWT_PUBLIC_KEY_PATH in .envを設定することにより、キーファイルのカスタムパスを提供することもできます。キーの1つまたは両方が見つからない場合、キーが生成されます。デフォルトでは、 RS256アルゴリズムが使用されますが、 JWT_ALGORITHMを設定して他の公開キーアルゴリズムを使用できます。
デフォルトでは、各トークンは120秒間有効です。 JWT_EXPIRES_IN in .envを設定して、これを調整できます。
トークンは、 /トークンのエンドポイントを介して、またはタイプtokenのWebSocketリクエストを使用して受信します。さらに、ユーザーがログインした後、最後のトークンが期限切れになる前に定期的にトークンを介してトークンが送信されます。
例トークンを確認する方法:
import jwt from "jsonwebtoken"
// token, e.g. from user request
let token = "..."
// get public key from file or endpoint
let publicKey = "..."
jwt . verify ( token , publicKey , ( error , decoded ) => {
if ( error ) {
// handle error
// ...
} else {
let { user , iat , exp } = decoded
// user is the user object
// iat is the issued timestamp
// exp is the expiration timestamp
// ...
}
} )または、Passport-JWTを使用することもできます(例に従います)。
ログインサーバーに関する一般的な情報を含むランディングページを表示します。
ユーザーアカウント(すでに認証されている場合)を管理するサイトを表示するか、 /login (認証されていない場合)にリダイレクトします。
ユーザーのセッション(認証されている場合)を管理するサイトを表示するか、 /loginにリダイレクト(認証されていない場合)。
ログインするサイト(認証されていない場合)を表示するか、 /account (認証されている場合)に指示します。
クエリパラメーターredirect_uriが指定されている場合、ログインが成功した後、サイトは指定されたURIにリダイレクトされます。 (パラメーターが指定されているが空の場合、紹介者をURIとして使用します。)
プロバイダーのログインページを表示します。 OAUTHプロバイダーの場合、このページはプロバイダーのページにリダイレクトして身元を接続し、 /login/:provider/returnにリダイレクトします。資格情報を使用するプロバイダーの場合、これにはログインフォームが表示されます。
このページは、 redirect_uriも処理します(上記を参照/login )。
資格情報を使用したプロバイダーのエンドポイントを投稿します。成功した場合、 /accountにリダイレクトします。そうしないと/login/:providerにリダイレクトされます。
プロバイダーをユーザーから切断し、 /accountにリダイレクトします。
ユーザーをアカウントから記録します。セッションは、WebSocketsに使用されるため残されることに注意してください。これにより、ユーザーがログアウトした場合でも、アプリケーションが現在のセッションのアクティブなWebSocketにイベントを送信できます。
ユーザーアカウントを削除するサイトを表示します。
ユーザーアカウントの削除をコミットし、 /loginにリダイレクトします。
サーバーは、各OAUTHプロバイダーにOAUTHリダイレクトエンドポイント(リダイレクトURI)を提供します。
OAUTHリクエストのコールバックエンドポイント。接続されたアイデンティティをユーザーに保存し(または必要に応じて新しいユーザーを作成します)、 /accountにリダイレクトします。
HTTP APIおよびWebSocket APIに対して直接プログラミングする前に、ログインクライアントJavaScriptブラウザーライブラリをご覧ください。ここで動作することができます(そのサイトのソース)。
キーtitle (ログインサーバーインスタンスのタイトル)、 env (環境、 developmentやproductionなど)、 publicKey (通常はRSA公開鍵)、およびalgorithm (jsonwebtokenアルゴリズムを使用)を備えたオブジェクトを返します。特定の公開キーに対応する秘密鍵は、JWTSに署名するときに使用されます。
利用可能なプロバイダーのリストを返します(機密情報を取り除きます)。
現在ログインしているユーザーを返します。ユーザーがログインされていない場合、404エラーを返します。
特定のユーザーを返します。現在、自分のユーザーIDに制限されています。
特定のユーザーを調整します。同じユーザーが現在ログインされている場合にのみ使用できます。プロパティの変更を許可: name (他のすべては無視されます)。
現在のセッションを除き、現在のユーザーのすべてのセッションを削除します。
SessionID :id (現在のユーザーのセッションである必要があります)でセッションを削除します。
JSON Webトークンを形式で返します。
{
"token" : " <JWT> " ,
"expiresIn" : 120
}参照:JWTS。
トークン自体には、 userプロパティ(現在ログインしているユーザーに関する情報が含まれているか、ユーザーがログインしていない場合はnull)と、WebSocket接続内で認証するために必要なsessionIDプロパティが含まれます。
Base URL /のWebSocket APIは、現在のユーザーまたはセッションに関するイベントを送信します。イベントは、JSONエンコードされた文字列として送信されます。
{
"type" : " event name (see below) " ,
"date" : " date (as ISOString) " ,
"data" : {
"user" : {
"uri" : " URI of user " ,
"name" : " name of user " ,
"identities" : {
"xzy" : {
"id" : " ID of user for provider xzy " ,
"uri" : " URI or profile URL of user for provider xzy " ,
"name" : " display name of user for provider xzy (if available) " ,
"username" : " username of user for provider xzy (if available) "
}
}
}
}
}open -WebSocket接続が確立された後に送信され、 ws.onopenの代わりにこれを使用してください!loggedInユーザーがログインしたときに送信されます(ユーザーがすでにログインしている場合は、WebSocketを確立した直後に送信されます)loggedOutユーザーがログアウトしたときに送信されます(ユーザーがログインしていない場合は、WebSocketを確立した直後に送信されます)updated - ユーザーが更新されたときに送信されました(例:新しいIDなどを追加)providers - WebSocket接続が確立された後に送信されました(利用可能なプロバイダーのリストを備えたプロパティdata.providersで構成されています。about -WebSocket接続が確立された後に送信されました(プロパティdata GET /ABORTと同じ形式になります)token - ユーザーがログインしたときに送信された後、前のトークンが失効する前に間隔で間隔で送信されます(プロパティdata Get /Tokenと同じ形式になります)authenticated - 認証を要求するときに成功として送信されます(以下を参照)pongタイプpingのリクエストへの回答として送信されます(WebSocketが古くなったかどうかを判断するために使用できます)sessionAboutToExpire現在関連付けられているセッションが期限切れになったときに送信error - WebSocketを介して不正なメッセージへの回答として送信されます(エラーメッセージ付きのプロパティdata.message 。WebSocketにリクエストを送信することもできます。これらはまた、次の形式でJSONエンコードされた文字列でなければなりません。
{
"type" : " name of request "
}これは、Get /Tokenから取得したJWTを使用して現在のWebSocketを特定のセッションに関連付ける特別なリクエストです(リクエストオブジェクトが必要なプロパティtokenが必要です)
Websocketがログインサーバーとは異なるドメインから使用される場合、 authenticate要求が必要になることがあります。その場合、トークンはAPIを介して要求される必要があります(例:オプションcredentials: "include"またはaxios with withCredentials: true )。トークンには、暗号化されたSessionIDが含まれ、その後、WebSocket接続に関連付けられます。 Webアプリケーションからのワークフローがどのように見えるかについての例を次に示します:https://coli-conc.gbv.de/login/api
以下は、WebSocketに接続する方法に関する簡単な例です。
// Assumes server is run on localhost:3005
let socket = new WebSocket ( "ws://localhost:3005" )
socket . addEventListener ( "message" , ( message ) => {
try {
let event = JSON . parse ( message )
alert ( event . event , event . user && event . user . uri )
} catch ( error ) {
console . warn ( "Error parsing WebSocket message" , message )
}
} ) PRが受け入れられました。
devブランチを基礎として使用してください。 devからの変更は、新しいリリースのためにのみmasterに統合されます。メンテナーのみ
開発中にdev部門で作業してください(または、さらに良いことに、機能ブランチで開発し、準備ができたらdevに合流してください)。
新しいリリースの準備ができたら(つまり、機能が終了し、 devにマージされ、すべてのテストが成功します)、含まれたリリーススクリプト(必要に応じて「マイナー」または「メジャー」に「パッチ」を置き換えます)を実行します):
npm run release:patchこれは:
devていることを確認してくださいdev最新であることを確認してくださいnpm version patch (または「マイナー」/「メジャー」)を実行するdevに変更をプッシュしますmasterに切り替えますdevからの変更をマージしますmasterを押しますdevに戻りますこれを実行した後、GitHub Actionsは自動的に新しいGitHubリリースドラフトを作成します。リリースを手動で編集して公開してください。
MIT©2019 VerbundzentraleDesGBV(VZG)