Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Raphael Ochsenbein
openid-connect-playground
Commits
28de03d6
Verified
Commit
28de03d6
authored
Feb 22, 2019
by
Raphael Ochsenbein
Browse files
Make openid module config depending on environment, optimize toast
parent
3fb03cff
Pipeline
#636
failed with stages
in 58 seconds
Changes
12
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
api/server.js
View file @
28de03d6
...
...
@@ -18,21 +18,32 @@ const checkJwt = jwt({
}),
// Validate the audience and the issuer
audience
:
'
https://
dev-l-3l8u04.eu.auth0.com/api/v2
/
'
,
// replace with your API's audience, available at Dashboard > APIs
audience
:
'
https://
openid.akehir.com:55001
/
'
,
// replace with your API's audience, available at Dashboard > APIs
issuer
:
'
https://dev-l-3l8u04.eu.auth0.com/
'
,
algorithms
:
[
'
RS256
'
]
// we are using RS256 to sign our tokens
});
app
.
all
(
'
/*
'
,
function
(
req
,
res
,
next
)
{
res
.
header
(
"
Access-Control-Allow-Origin
"
,
"
*
"
);
res
.
header
(
"
Access-Control-Allow-Headers
"
,
"
Origin, X-Requested-With, Content-Type, Accept, Authorization
"
);
next
();
});
// create retrieve balance endpoint
app
.
get
(
'
/balance
'
,
checkJwt
,
jwtAuthz
([
'
view:balance
'
]),
function
(
req
,
res
)
{
// code that retrieves the user's balance and sends it back to the calling app
res
.
status
(
201
).
send
({
message
:
"
This is the GET /balance endpoint
"
});
res
.
status
(
201
).
send
({
message
:
"
{
\"
message
\"
:
\"
This is the GET /balance endpoint
\"
"
});
});
// create transfer funds endpoint
app
.
post
(
'
/transfer
'
,
checkJwt
,
jwtAuthz
([
'
transfer:funds
'
]),
function
(
req
,
res
)
{
// code that transfers funds from one account to another
checkJwt
.
res
.
status
(
201
).
send
({
message
:
"
This is the POST /transfer endpoint
"
});
});
...
...
src/app/app.component.html
View file @
28de03d6
...
...
@@ -3,13 +3,13 @@
Welcome to {{ title }}!
</h1>
</div>
<h2>
Log In / Log Out
</h2>
<!--<button [ibmButton]="'primary'" [size]="'normal'" (click)="showToast()">Toast</button><span> </span>-->
<hr/>
<button
[ibmButton]=
"'primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Log In
</button>
<button
[ibmButton]=
"'danger--primary'"
[size]=
"'normal'"
(click)=
"logoutPopup()"
>
Log Out
</button>
<hr/>
<button
[ibmButton]=
"'primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Call 1FA API
</button>
<button
[ibmButton]=
"'danger--primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Call 2FA API
</button>
<button
[ibmButton]=
"'primary'"
[size]=
"'normal'"
(click)=
"call1FAAPI()"
>
Call 1FA API
</button>
<button
[ibmButton]=
"'danger--primary'"
[size]=
"'normal'"
(click)=
"call2FAAPI()"
>
Call 2FA API
</button>
<hr/>
<button
[ibmButton]=
"'primary'"
[size]=
"'normal'"
(click)=
"check2FA()"
>
Check 2FA
</button>
<button
[ibmButton]=
"'danger--primary'"
[size]=
"'normal'"
(click)=
"loginPopup2fA()"
>
Login Request 2FA
</button>
<hr/>
<button
[ibmButton]=
"'primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Check 2FA
</button>
<button
[ibmButton]=
"'danger--primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Login Request 2FA
</button>
src/app/app.component.ts
View file @
28de03d6
import
{
Component
}
from
'
@angular/core
'
;
import
{
Component
,
OnDestroy
}
from
'
@angular/core
'
;
import
{
OidcFacade
}
from
'
ng-oidc-client
'
;
import
{
ToastService
}
from
'
./toast
'
;
import
{
merge
,
Observable
,
of
,
Subscription
}
from
'
rxjs
'
;
import
{
catchError
,
mergeMap
,
take
}
from
'
rxjs/operators
'
;
import
{
environment
}
from
'
.././environments/environment
'
;
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
isArray
}
from
'
util
'
;
@
Component
({
selector
:
'
app-root
'
,
templateUrl
:
'
./app.component.html
'
,
styleUrls
:
[
'
./app.component.scss
'
]
})
export
class
AppComponent
{
export
class
AppComponent
implements
OnDestroy
{
private
audienceApi
=
'
https://openid.akehir.com:55001/
'
;
private
audience
=
{
audience
:
this
.
audienceApi
};
title
=
'
openid-connect-playground
'
;
loadingSub
:
Subscription
;
expiringSub
:
Subscription
;
expiredSub
:
Subscription
;
errorSub
:
Subscription
;
loggedInSub
:
Subscription
;
identitySub
:
Subscription
;
constructor
(
private
oidcFacade
:
OidcFacade
,
private
toast
:
ToastService
,
)
{}
private
http
:
HttpClient
,
)
{
this
.
loadingSub
=
this
.
oidcFacade
.
loading$
.
subscribe
((
data
)
=>
{
console
.
log
(
'
Loading
'
,
data
);
});
this
.
expiringSub
=
this
.
oidcFacade
.
expiring$
.
subscribe
((
data
)
=>
{
console
.
log
(
'
Expiring
'
,
data
);
});
this
.
expiredSub
=
this
.
oidcFacade
.
expired$
.
subscribe
((
data
)
=>
{
console
.
log
(
'
Expired
'
,
data
);
});
this
.
loggedInSub
=
this
.
oidcFacade
.
loggedIn$
.
subscribe
((
data
)
=>
{
console
.
log
(
'
Logged In
'
,
data
);
});
this
.
errorSub
=
this
.
oidcFacade
.
errors$
.
subscribe
((
data
)
=>
{
console
.
log
(
'
Error
'
,
data
);
this
.
toast
.
show
({
type
:
'
error
'
,
title
:
'
Error
'
,
caption
:
`
${
JSON
.
stringify
(
data
)}
`
,
});
});
this
.
identitySub
=
this
.
oidcFacade
.
identity$
.
subscribe
((
data
)
=>
{
console
.
log
(
'
Identity
'
,
data
);
});
}
loginPopup
()
{
this
.
toast
.
show
({
...
...
@@ -21,7 +67,10 @@ export class AppComponent {
title
:
'
Log In
'
,
caption
:
'
Logging in.
'
,
});
this
.
oidcFacade
.
signinPopup
();
this
.
oidcFacade
.
signinPopup
({
extraQueryParams
:
this
.
audience
,
});
}
logoutPopup
()
{
...
...
@@ -33,12 +82,124 @@ export class AppComponent {
this
.
oidcFacade
.
signoutPopup
();
}
showToast
()
{
check2FA
()
{
const
userManager
=
this
.
oidcFacade
.
getUserManager
();
userManager
.
getUser
().
then
((
user
)
=>
{
if
(
user
)
{
if
(
user
.
profile
)
{
if
(
user
.
profile
.
amr
)
{
if
(
user
.
profile
.
amr
.
indexOf
(
'
mfa
'
)
>=
0
)
{
this
.
toast
.
show
({
type
:
'
success
'
,
title
:
'
2FA
'
,
caption
:
'
You are logged in with 2FA!
'
,
});
}
else
{
this
.
toast
.
show
({
type
:
'
error
'
,
title
:
'
2FA
'
,
caption
:
'
You are logged in with 1FA!
'
,
});
}
}
else
{
this
.
toast
.
show
({
type
:
'
error
'
,
title
:
'
2FA
'
,
caption
:
'
You are logged in with 1FA!
'
,
});
}
}
else
{
this
.
toast
.
show
({
type
:
'
error
'
,
title
:
'
2FA
'
,
caption
:
'
Your profile could not be decoded
'
,
});
}
}
else
{
this
.
toast
.
show
({
type
:
'
error
'
,
title
:
'
2FA
'
,
caption
:
'
You are not logged in!
'
,
});
}
});
}
loginPopup2fA
()
{
this
.
toast
.
show
({
type
:
'
info
'
,
title
:
'
Test
'
,
caption
:
'
T
esting
'
,
type
:
'
warn
'
,
title
:
'
Log In
'
,
caption
:
'
Logging in, requ
esting
2FA.
'
,
});
this
.
oidcFacade
.
signinPopup
(
{
scope
:
'
openid profile offline_access view:balance transfer:funds
'
,
extraQueryParams
:
this
.
audience
,
acr_values
:
'
http://schemas.openid.net/pape/policies/2007/06/multi-factor
'
,
});
}
call1FAAPI
()
{
this
.
apiCall
(
'
/balance
'
);
}
call2FAAPI
()
{
this
.
apiCall
(
'
/transfer
'
);
}
apiCall
(
api
:
string
)
{
this
.
urlCall
(
this
.
getApi
(
this
.
getUrl
(
api
),
api
));
}
getUrl
(
api
:
string
)
{
if
(
environment
.
production
)
{
return
'
https://openid.akehir.com:55001
'
;
}
return
'
http://localhost:55001
'
;
}
urlCall
(
api
:
Observable
<
{}
>
)
{
api
.
pipe
(
catchError
((
error
)
=>
{
console
.
log
(
'
api error
'
,
error
);
this
.
toast
.
show
({
type
:
'
error
'
,
title
:
'
API Call Error
'
,
caption
:
`
${
error
.
message
}
`
,
});
return
of
(
false
);
})
).
subscribe
((
data
)
=>
{
if
(
data
)
{
console
.
log
(
'
api data
'
,
data
);
this
.
toast
.
show
({
type
:
'
success
'
,
title
:
'
API Call
'
,
caption
:
`Received:
${
JSON
.
stringify
(
data
)}
`
,
});
}
});
}
getApi
(
url
:
string
,
api
:
string
)
{
if
(
api
===
'
/transfer
'
)
{
return
this
.
http
.
post
(
url
+
api
,
{});
}
else
if
(
api
===
'
/balance
'
)
{
return
this
.
http
.
get
(
url
+
api
);
}
return
of
({});
}
ngOnDestroy
():
void
{
this
.
loadingSub
.
unsubscribe
();
this
.
expiringSub
.
unsubscribe
();
this
.
expiredSub
.
unsubscribe
();
this
.
errorSub
.
unsubscribe
();
this
.
loggedInSub
.
unsubscribe
();
this
.
identitySub
.
unsubscribe
();
}
}
src/app/app.module.ts
View file @
28de03d6
...
...
@@ -5,10 +5,10 @@ import { AppComponent } from './app.component';
import
{
ActionReducerMap
,
StoreModule
}
from
'
@ngrx/store
'
;
import
{
Log
,
WebStorageStateStore
}
from
'
oidc-client
'
;
import
{
EffectsModule
}
from
'
@ngrx/effects
'
;
import
{
NgOidcClientModule
}
from
'
ng-oidc-client
'
;
import
{
Config
as
OidcConfig
,
NgOidcClientModule
}
from
'
ng-oidc-client
'
;
import
{
routerReducer
,
RouterReducerState
}
from
'
@ngrx/router-store
'
;
import
{
OidcGuardService
}
from
'
./oidc-guard.service
'
;
import
{
HTTP_INTERCEPTORS
}
from
'
@angular/common/http
'
;
import
{
HTTP_INTERCEPTORS
,
HttpClientModule
}
from
'
@angular/common/http
'
;
import
{
OidcInterceptorService
}
from
'
./oidc-interceptor.service
'
;
import
{
OidcEffectsService
}
from
'
./oidc-effects.service
'
;
import
{
metaReducers
}
from
'
./logout.metareducer
'
;
...
...
@@ -16,7 +16,8 @@ import {ButtonModule, NotificationModule, NotificationService} from 'carbon-comp
import
{
ToastModule
}
from
'
./toast
'
;
import
{
FormsModule
}
from
'
@angular/forms
'
;
import
{
BrowserAnimationsModule
}
from
'
@angular/platform-browser/animations
'
;
import
{
environment
}
from
'
../environments/environment
'
;
import
{
ConfiguredOidcModuleModule
}
from
'
./configured-oidc.module
'
;
// Setup done according to https://www.npmjs.com/package/ng-oidc-client
...
...
@@ -28,7 +29,6 @@ export const rootStore: ActionReducerMap<State> = {
router
:
routerReducer
};
// export const storage = new WebStorageStateStore({store: window.localStorage});
@
NgModule
({
declarations
:
[
...
...
@@ -38,28 +38,12 @@ export const rootStore: ActionReducerMap<State> = {
BrowserModule
,
FormsModule
,
BrowserAnimationsModule
,
HttpClientModule
,
ButtonModule
,
ToastModule
.
forRoot
(),
StoreModule
.
forRoot
(
rootStore
,
{
metaReducers
}),
EffectsModule
.
forRoot
([
OidcEffectsService
]),
NgOidcClientModule
.
forRoot
({
oidc_config
:
{
authority
:
'
https://dev-l-3l8u04.eu.auth0.com
'
,
client_id
:
'
FYg99lRIvbUwY4c0h5PkBArUOPnCcpH3
'
,
redirect_uri
:
'
http://localhost:4200/callback.html
'
,
response_type
:
'
id_token token
'
,
scope
:
'
openid profile offline_access api1
'
,
post_logout_redirect_uri
:
'
http://localhost:4200/signout-callback.html
'
,
silent_redirect_uri
:
'
http://localhost:4200/renew-callback.html
'
,
accessTokenExpiringNotificationTime
:
10
,
automaticSilentRenew
:
true
,
// userStore: storage,
},
// log: {
// logger: window.console,
// level: 0,
// },
}),
ConfiguredOidcModuleModule
.
forRoot
(
environment
),
],
providers
:
[
OidcGuardService
,
...
...
src/app/configured-oidc.module.ts
0 → 100644
View file @
28de03d6
import
{
ModuleWithProviders
,
NgModule
}
from
'
@angular/core
'
;
import
{
NgOidcClientModule
}
from
'
ng-oidc-client
'
;
@
NgModule
(
{
imports
:
[
NgOidcClientModule
.
forRoot
({
oidc_config
:
{
authority
:
'
https://dev-l-3l8u04.eu.auth0.com
'
,
client_id
:
'
FYg99lRIvbUwY4c0h5PkBArUOPnCcpH3
'
,
redirect_uri
:
'
https://openid.akehir.com/callback.html
'
,
response_type
:
'
id_token token
'
,
scope
:
'
openid profile offline_access view:balance
'
,
post_logout_redirect_uri
:
'
https://openid.akehir.com/signout-callback.html
'
,
silent_redirect_uri
:
'
https://openid.akehir.com/renew-callback.html
'
,
accessTokenExpiringNotificationTime
:
10
,
automaticSilentRenew
:
true
,
},
})
],
providers
:
[]
}
)
export
class
ConfiguredOidcModuleForProd
{}
@
NgModule
(
{
imports
:
[
NgOidcClientModule
.
forRoot
({
oidc_config
:
{
authority
:
'
https://dev-l-3l8u04.eu.auth0.com
'
,
client_id
:
'
FYg99lRIvbUwY4c0h5PkBArUOPnCcpH3
'
,
redirect_uri
:
'
http://localhost:4200/callback.html
'
,
response_type
:
'
id_token token
'
,
scope
:
'
openid profile offline_access view:balance
'
,
post_logout_redirect_uri
:
'
http://localhost:4200/signout-callback.html
'
,
silent_redirect_uri
:
'
http://localhost:4200/renew-callback.html
'
,
accessTokenExpiringNotificationTime
:
10
,
automaticSilentRenew
:
true
,
},
}),
],
providers
:
[
]
}
)
export
class
ConfiguredOidcModuleForDev
{}
@
NgModule
({
imports
:
[
ConfiguredOidcModuleForProd
,
ConfiguredOidcModuleForDev
],
declarations
:
[],
entryComponents
:
[]
})
export
class
ConfiguredOidcModuleModule
{
public
static
forRoot
(
environment
)
{
return
{
ngModule
:
(
environment
.
production
?
ConfiguredOidcModuleForProd
:
ConfiguredOidcModuleForDev
)
};
}
}
src/app/oidc-interceptor.service.ts
View file @
28de03d6
import
{
switchMap
}
from
'
rxjs/operators
'
;
import
{
switchMap
,
tap
}
from
'
rxjs/operators
'
;
import
{
HttpEvent
,
HttpHandler
,
HttpInterceptor
,
HttpRequest
}
from
'
@angular/common/http
'
;
import
{
Observable
}
from
'
rxjs
'
;
import
{
OidcFacade
}
from
'
ng-oidc-client
'
;
...
...
src/app/toast/toast.component.ts
View file @
28de03d6
...
...
@@ -8,7 +8,7 @@ import { toastAnimations, ToastAnimationState } from './toast.animation';
@
Component
({
selector
:
'
app-toast
'
,
template
:
`
<ibm-toast [notificationObj]="data"
<ibm-toast [notificationObj]="data"
(close)="close()"
[@fadeAnimation]="{value: animationState, params:
{ fadeIn: toastConfig.animation.fadeIn, fadeOut: toastConfig.animation.fadeOut }}"
(@fadeAnimation.done)="onFadeFinished($event)">
...
...
@@ -25,14 +25,12 @@ export class ToastComponent implements OnInit, OnDestroy {
readonly
ref
:
ToastRef
,
@
Inject
(
_TOAST_CONFIG_TOKEN
)
public
toastConfig
:
MyToastConfig
)
{
// this.iconType = data.type === 'success' ? 'done' : data.type;
// somehow empty injection of the config... maybe issue with carbon?
this
.
toastConfig
=
{...
defaultToastConfig
,
...
this
.
toastConfig
};
}
ngOnInit
()
{
this
.
intervalId
=
setTimeout
(()
=>
this
.
animationState
=
'
closing
'
,
5000
);
this
.
intervalId
=
setTimeout
(()
=>
this
.
animationState
=
'
closing
'
,
this
.
toastConfig
.
stayTime
);
}
ngOnDestroy
()
{
...
...
src/app/toast/toast.config.ts
View file @
28de03d6
...
...
@@ -20,6 +20,7 @@ export class ToastData {
export
type
ToastType
=
'
warning
'
|
'
info
'
|
'
success
'
;
export
interface
MyToastConfig
{
stayTime
?:
number
;
position
?:
{
top
:
number
;
right
:
number
;
...
...
@@ -31,13 +32,14 @@ export interface MyToastConfig {
}
export
const
defaultToastConfig
:
MyToastConfig
=
{
stayTime
:
1500
,
position
:
{
top
:
20
,
right
:
20
,
},
animation
:
{
fadeOut
:
25
00
,
fadeIn
:
3
00
,
fadeOut
:
10
00
,
fadeIn
:
2
00
,
},
};
...
...
src/app/toast/toast.service.ts
View file @
28de03d6
...
...
@@ -5,11 +5,16 @@ import { ComponentPortal, PortalInjector } from '@angular/cdk/portal';
import
{
ToastComponent
}
from
'
./toast.component
'
;
import
{
ToastData
,
_TOAST_CONFIG_TOKEN
,
MyToastConfig
,
defaultToastConfig
}
from
'
./toast.config
'
;
import
{
ToastRef
}
from
'
./toast.ref
'
;
import
{
interval
,
Observable
,
ReplaySubject
,
Subject
}
from
'
rxjs
'
;
import
{
auditTime
,
debounceTime
,
delay
,
delayWhen
,
throttleTime
}
from
'
rxjs/operators
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
ToastService
{
private
lastToast
:
ToastRef
;
private
toastsSubject
:
Subject
<
ToastData
>
=
new
ReplaySubject
(
1
);
private
trefSubject
:
Subject
<
ToastRef
>
=
new
ReplaySubject
(
1
);
private
lastToastTime
:
number
;
constructor
(
private
overlay
:
Overlay
,
...
...
@@ -19,9 +24,27 @@ export class ToastService {
// console.log(parentInjector, this.toastConfig);
// somehow empty injection of the config... maybe issue with carbon?
this
.
toastConfig
=
{...
defaultToastConfig
,
...
this
.
toastConfig
};
this
.
lastToastTime
=
performance
.
now
();
this
.
toastsSubject
.
pipe
(
delayWhen
((
data
)
=>
{
const
current
=
performance
.
now
();
const
diff
=
(
current
-
this
.
lastToastTime
)
>
100
;
if
(
diff
)
{
this
.
lastToastTime
=
current
;
return
interval
(
0
);
}
this
.
lastToastTime
=
current
+
100
;
return
interval
(
100
);
}),
).
subscribe
((
data
)
=>
{
const
ref
=
this
.
display
(
data
);
this
.
trefSubject
.
next
(
ref
);
});
}
show
(
data
:
ToastData
)
{
display
(
data
:
ToastData
)
:
ToastRef
{
const
positionStrategy
=
this
.
getPositionStrategy
();
const
overlayRef
=
this
.
overlay
.
create
({
positionStrategy
});
...
...
@@ -35,6 +58,13 @@ export class ToastService {
return
toastRef
;
}
show
(
data
:
ToastData
):
Observable
<
ToastRef
>
{
this
.
toastsSubject
.
next
(
data
);
return
this
.
trefSubject
.
asObservable
();
}
getPositionStrategy
()
{
return
this
.
overlay
.
position
()
.
global
()
...
...
src/static/callback.html
View file @
28de03d6
...
...
@@ -17,7 +17,7 @@
var
config
=
{
userStore
:
new
Oidc
.
WebStorageStateStore
({
store
:
window
.
localStorage
})
}
}
;
if
((
Oidc
&&
Oidc
.
Log
&&
Oidc
.
Log
.
logger
))
{
Oidc
.
Log
.
logger
=
console
;
...
...
src/static/renew-callback.html
View file @
28de03d6
...
...
@@ -14,7 +14,7 @@
<script>
var
config
=
{
userStore
:
new
Oidc
.
WebStorageStateStore
({
store
:
window
.
localStorage
})
}
}
;
new
Oidc
.
UserManager
(
config
).
signinSilentCallback
().
catch
(
function
(
e
)
{
console
.
error
(
e
);
});
...
...
src/static/signout-callback.html
View file @
28de03d6
...
...
@@ -17,7 +17,7 @@
var
config
=
{
userStore
:
new
Oidc
.
WebStorageStateStore
({
store
:
window
.
localStorage
})
}
}
;
if
((
Oidc
&&
Oidc
.
Log
&&
Oidc
.
Log
.
logger
))
{
Oidc
.
Log
.
logger
=
console
;
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment