mirror of
https://github.com/documize/community.git
synced 2025-07-21 14:19:43 +02:00
sync users wip
This commit is contained in:
parent
1c6e1c7bd7
commit
945fadaf00
6 changed files with 166 additions and 30 deletions
|
@ -25,11 +25,15 @@ export default Ember.Component.extend({
|
||||||
KeycloakRealmError: computed.empty('keycloakConfig.realm'),
|
KeycloakRealmError: computed.empty('keycloakConfig.realm'),
|
||||||
KeycloakClientIdError: computed.empty('keycloakConfig.clientId'),
|
KeycloakClientIdError: computed.empty('keycloakConfig.clientId'),
|
||||||
KeycloakPublicKeyError: computed.empty('keycloakConfig.publicKey'),
|
KeycloakPublicKeyError: computed.empty('keycloakConfig.publicKey'),
|
||||||
|
KeycloakAdminUserError: computed.empty('keycloakConfig.adminUser'),
|
||||||
|
KeycloakAdminPasswordError: computed.empty('keycloakConfig.adminPassword'),
|
||||||
keycloakConfig: {
|
keycloakConfig: {
|
||||||
url: '',
|
url: '',
|
||||||
realm: '',
|
realm: '',
|
||||||
clientId: '',
|
clientId: '',
|
||||||
publicKey: '',
|
publicKey: '',
|
||||||
|
adminUser: '',
|
||||||
|
adminPassword: ''
|
||||||
},
|
},
|
||||||
|
|
||||||
didReceiveAttrs() {
|
didReceiveAttrs() {
|
||||||
|
@ -89,16 +93,14 @@ export default Ember.Component.extend({
|
||||||
this.$("#keycloak-publicKey").focus();
|
this.$("#keycloak-publicKey").focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.get('KeycloakAdminUserError')) {
|
||||||
// let pk = this.get('keycloakConfig.publicKey');
|
this.$("#keycloak-admin-user").focus();
|
||||||
// if (is.not.startWith(pk, '-----BEGIN PUBLIC KEY-----')) {
|
return;
|
||||||
// pk = '-----BEGIN PUBLIC KEY-----' + pk;
|
}
|
||||||
// }
|
if (this.get('KeycloakAdminPasswordError')) {
|
||||||
// if (is.not.endWith(pk, '-----END PUBLIC KEY-----')) {
|
this.$("#keycloak-admin-password").focus();
|
||||||
// pk = pk + '-----END PUBLIC KEY-----' ;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// this.set('keycloakConfig.publicKey', pk);
|
|
||||||
|
|
||||||
config = Ember.copy(this.get('keycloakConfig'));
|
config = Ember.copy(this.get('keycloakConfig'));
|
||||||
Ember.set(config, 'publicKey', encoding.Base64.encode(this.get('keycloakConfig.publicKey')));
|
Ember.set(config, 'publicKey', encoding.Base64.encode(this.get('keycloakConfig.publicKey')));
|
||||||
|
|
|
@ -15,7 +15,8 @@ import constants from '../../../utils/constants';
|
||||||
export default Ember.Route.extend({
|
export default Ember.Route.extend({
|
||||||
session: Ember.inject.service(),
|
session: Ember.inject.service(),
|
||||||
appMeta: Ember.inject.service(),
|
appMeta: Ember.inject.service(),
|
||||||
kcAuth: Ember.inject.service(),
|
kcAuth: Ember.inject.service(),
|
||||||
|
localStorage: Ember.inject.service(),
|
||||||
queryParams: {
|
queryParams: {
|
||||||
mode: {
|
mode: {
|
||||||
refreshModel: false
|
refreshModel: false
|
||||||
|
@ -33,11 +34,16 @@ export default Ember.Route.extend({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.get('mode') === 'reject') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.get('kcAuth').boot(JSON.parse(authConfig)).then((kc) => {
|
this.get('kcAuth').boot(JSON.parse(authConfig)).then((kc) => {
|
||||||
if (!kc.authenticated) {
|
if (!kc.authenticated) {
|
||||||
this.get('kcAuth').login().then(() => {
|
this.get('kcAuth').login().then(() => {
|
||||||
}, (reject) => {
|
}, (reject) => {
|
||||||
console.log(reject);
|
this.get('localStorage').storeSessionItem('kc-error', reject);
|
||||||
|
this.transitionTo('auth.keycloak', { queryParams: { mode: 'reject' }});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,16 +53,23 @@ export default Ember.Route.extend({
|
||||||
this.get('audit').record("logged-in-keycloak");
|
this.get('audit').record("logged-in-keycloak");
|
||||||
this.transitionTo('folders');
|
this.transitionTo('folders');
|
||||||
}, (reject) => {
|
}, (reject) => {
|
||||||
debugger;
|
this.get('localStorage').storeSessionItem('kc-error', reject);
|
||||||
console.log(">>>>> Documize Keycloak authentication failure");
|
this.transitionTo('auth.keycloak', { queryParams: { mode: 'reject' }});
|
||||||
this.transitionTo('auth.login');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}, (err) => {
|
}, (reject) => {
|
||||||
console.log(err);
|
this.get('localStorage').storeSessionItem('kc-error', reject);
|
||||||
|
this.transitionTo('auth.keycloak', { queryParams: { mode: 'reject' }});
|
||||||
});
|
});
|
||||||
}, (reason) => {
|
}, (reject) => {
|
||||||
console.log(reason);
|
this.get('localStorage').storeSessionItem('kc-error', reject);
|
||||||
|
this.transitionTo('auth.keycloak', { queryParams: { mode: 'reject' }});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
model() {
|
||||||
|
return {
|
||||||
|
mode: this.get('mode')
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
<div class="sso-box">
|
{{#if (is-equal model.mode 'login')}}
|
||||||
<p>Authenticating with Keycloak...</p>
|
<div class="sso-box">
|
||||||
<img src="/assets/img/busy-gray.gif" />
|
<p>Authenticating with Keycloak...</p>
|
||||||
</div>
|
<img src="/assets/img/busy-gray.gif" />
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if (is-equal model.mode 'reject')}}
|
||||||
|
<div class="sso-box">
|
||||||
|
<p>Keycloak Authentication Failure</p>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import constants from '../../../utils/constants';
|
||||||
export default Ember.Route.extend({
|
export default Ember.Route.extend({
|
||||||
appMeta: Ember.inject.service(),
|
appMeta: Ember.inject.service(),
|
||||||
kcAuth: Ember.inject.service(),
|
kcAuth: Ember.inject.service(),
|
||||||
|
localStorage: Ember.inject.service(),
|
||||||
showLogin: false,
|
showLogin: false,
|
||||||
|
|
||||||
beforeModel(/*transition*/) {
|
beforeModel(/*transition*/) {
|
||||||
|
@ -28,13 +29,16 @@ export default Ember.Route.extend({
|
||||||
this.get('kcAuth').boot(JSON.parse(authConfig)).then(() => {
|
this.get('kcAuth').boot(JSON.parse(authConfig)).then(() => {
|
||||||
this.get('kcAuth').login().then(() => {
|
this.get('kcAuth').login().then(() => {
|
||||||
}, (reject) => {
|
}, (reject) => {
|
||||||
console.log(reject);
|
this.get('localStorage').storeSessionItem('kc-error', reject);
|
||||||
|
this.transitionTo('auth.keycloak', { queryParams: { mode: 'reject' }});
|
||||||
});
|
});
|
||||||
}, (reject) => {
|
}, (reject) => {
|
||||||
console.log(reject);
|
this.get('localStorage').storeSessionItem('kc-error', reject);
|
||||||
|
this.transitionTo('auth.keycloak', { queryParams: { mode: 'reject' }});
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.set('showLogin', true);
|
this.set('showLogin', true);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
{{#if isKeycloakProvider}}
|
{{#if isKeycloakProvider}}
|
||||||
<div class="form-header">
|
<div class="form-header">
|
||||||
<div class="title">Keycloak Configuration</div>
|
<div class="title">Keycloak Configuration</div>
|
||||||
<div class="tip">Connection parameters</div>
|
<div class="tip">Connection parameters — create a documize user in Master realm with 'manage-users' role against target realm</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-control">
|
<div class="input-control">
|
||||||
<label>Keycloak Server URL</label>
|
<label>Keycloak Server URL</label>
|
||||||
|
@ -35,6 +35,16 @@
|
||||||
<div class="tip">Copy the RSA public key from Realm Settings → Keys</div>
|
<div class="tip">Copy the RSA public key from Realm Settings → Keys</div>
|
||||||
{{textarea id="keycloak-publicKey" type="text" value=keycloakConfig.publicKey rows=7 class=(if KeycloakPublicKeyError 'error')}}
|
{{textarea id="keycloak-publicKey" type="text" value=keycloakConfig.publicKey rows=7 class=(if KeycloakPublicKeyError 'error')}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="input-control">
|
||||||
|
<label>Keycloak Username</label>
|
||||||
|
<div class="tip">Used to connect with Keycloak and sync users with Documize</div>
|
||||||
|
{{input id="keycloak-admin-user" type="text" value=keycloakConfig.adminUser class=(if KeycloakAdminUserError 'error')}}
|
||||||
|
</div>
|
||||||
|
<div class="input-control">
|
||||||
|
<label>Keycloak Password</label>
|
||||||
|
<div class="tip">Used to connect with Keycloak and sync users with Documize</div>
|
||||||
|
{{input id="keycloak-admin-password" type="password" value=keycloakConfig.adminPassword class=(if KeycloakAdminPasswordError 'error')}}
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
<div class="regular-button button-blue" {{action 'onSave'}}>save</div>
|
<div class="regular-button button-blue" {{action 'onSave'}}>save</div>
|
||||||
|
|
|
@ -17,14 +17,18 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
"github.com/documize/community/core/api/endpoint/models"
|
"github.com/documize/community/core/api/endpoint/models"
|
||||||
"github.com/documize/community/core/api/entity"
|
"github.com/documize/community/core/api/entity"
|
||||||
"github.com/documize/community/core/api/request"
|
"github.com/documize/community/core/api/request"
|
||||||
"github.com/documize/community/core/api/util"
|
"github.com/documize/community/core/api/util"
|
||||||
"github.com/documize/community/core/log"
|
"github.com/documize/community/core/log"
|
||||||
"github.com/documize/community/core/utility"
|
"github.com/documize/community/core/utility"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthenticateKeycloak checks Keycloak authentication credentials.
|
// AuthenticateKeycloak checks Keycloak authentication credentials.
|
||||||
|
@ -158,6 +162,11 @@ func AuthenticateKeycloak(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = SyncUsers(ac)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("su", err)
|
||||||
|
}
|
||||||
|
|
||||||
writeSuccessBytes(w, json)
|
writeSuccessBytes(w, json)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,6 +249,79 @@ func addUser(p request.Persister, a keycloakAuthRequest) (u entity.User, err err
|
||||||
return p.GetUser(userID)
|
return p.GetUser(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SyncUsers gets list of Keycloak users for specified Realm, Client Id
|
||||||
|
func SyncUsers(c keycloakConfig) (err error) {
|
||||||
|
form := url.Values{}
|
||||||
|
form.Add("username", c.AdminUser)
|
||||||
|
form.Add("password", c.AdminPassword)
|
||||||
|
form.Add("client_id", "admin-cli")
|
||||||
|
form.Add("grant_type", "password")
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST",
|
||||||
|
fmt.Sprintf("%s/realms/master/protocol/openid-connect/token", c.URL),
|
||||||
|
bytes.NewBufferString(form.Encode()))
|
||||||
|
|
||||||
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
req.Header.Add("Content-Length", strconv.Itoa(len(form.Encode())))
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ka := keycloakAPIAuth{}
|
||||||
|
err = json.Unmarshal(body, &ka)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != http.StatusOK {
|
||||||
|
return errors.New("Keycloak authentication failed " + res.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err = http.NewRequest("GET",
|
||||||
|
fmt.Sprintf("%s/admin/realms/%s/users?max=500", c.URL, c.Realm),
|
||||||
|
nil)
|
||||||
|
|
||||||
|
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", ka.AccessToken))
|
||||||
|
|
||||||
|
client = &http.Client{}
|
||||||
|
res, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer res.Body.Close()
|
||||||
|
body, err = ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
u := []keycloakUser{}
|
||||||
|
err = json.Unmarshal(body, &u)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode != http.StatusOK {
|
||||||
|
return errors.New("Keycloak /users call failed " + res.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info(fmt.Sprintf("%d", res.StatusCode))
|
||||||
|
|
||||||
|
fmt.Println(fmt.Sprintf("%d len", len(u)))
|
||||||
|
fmt.Println(u[0].Email)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Data received via Keycloak client library
|
// Data received via Keycloak client library
|
||||||
type keycloakAuthRequest struct {
|
type keycloakAuthRequest struct {
|
||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
|
@ -254,8 +336,25 @@ type keycloakAuthRequest struct {
|
||||||
|
|
||||||
// Keycloak server configuration
|
// Keycloak server configuration
|
||||||
type keycloakConfig struct {
|
type keycloakConfig struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
Realm string `json:"realm"`
|
Realm string `json:"realm"`
|
||||||
ClientID string `json:"clientId"`
|
ClientID string `json:"clientId"`
|
||||||
PublicKey string `json:"publicKey"`
|
PublicKey string `json:"publicKey"`
|
||||||
|
AdminUser string `json:"adminUser"`
|
||||||
|
AdminPassword string `json:"adminPassword"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// keycloakAPIAuth is returned when authenticating with Keycloak REST API.
|
||||||
|
type keycloakAPIAuth struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// keycloakUser details user record returned by Keycloak
|
||||||
|
type keycloakUser struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Firstname string `json:"firstName"`
|
||||||
|
Lastname string `json:"lastName"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue