navikt / token-support Goto Github PK
View Code? Open in Web Editor NEWModules to support security token handling in NAV
License: MIT License
Modules to support security token handling in NAV
License: MIT License
BearerTokenClientHttpRequestInterceptor is activated and pulled in as a Bean if either
no.nav.security.jwt.dont-propagate-bearertoken is not set
or
no.nav.security.jwt.dont-propagate-bearertoken=true
By setting this value to either nothing or to 'true' one would assume that we "don't propagate bearer token", but that is not the case.
Fikse ConditonalOnProperty or rename the 'no.nav.security.jwt.dont-propagate-bearertoken' variable to something better like f.eks. 'no.nav.security.jwt.propagate-bearertoken' with default to false.
Making the project java 8 compliant will (possibly) make it easier for older applications to migrate from another security-framework.
This means that you loose the ability to use newer java features but this doesn't mean much at this point in time, as you can see in the proposed patch (ref:1). The patch is considered work in progress, but it should give an indication of how small this change really is.
It may be something I'm not aware of or haven't considered, but I'm willing to "do the heavy lifting" if the propose gets accepted.
Ref.
1: patped@c0e54c5
After the removal of the resourceUrl
property in ClientProperties
(token-client-core) we have gotten feedback that it should be reincluded as it proves handy to automatically choose the correct OAuth2 client when invoking an API.
Suggest to reintroduce this as an optional property.
Should upgrade project to latest java jdk
no.nav.security.token.support.core.validation.JwtTokenRetriever.lambda$containsCookieName$3(JwtTokenRetriever.java:63)
#191 implements support for meta annotations and annotations on superclasses/interfaces with the SpringJwtTokenAnnotationHandler
using the Spring utility class AnnotationsUtils
. Ideally this should be supported in the core module in the JwtTokenAnnotationHandler
without dependency on Spring classes, using JDK methods only.
It would have been very nice to be able to set expirythreshold also in the ktor-module, not only in the Spring-module. Any plans to add this feature?
There is already support for a "corporate" proxy per issuer so the global proxy for all issuers is no longer necessary (in addition the JVM supports proxy by using env/system properties)
The ProxyAwareResourceRetriever
can also be removed as the nimbus DefaultResourceRetriever
now supports proxy setup (it didnt earlier). Note that we need our own ResourceRetriever
in order to use the current test/mock setup in token-validation-test-support which requires overriding the resource retriever. This might change when #29 is implemented, preferably by using https://github.com/navikt/mock-oauth2-server instead of files etc.
Annoteringen @EnableJwtTokenValidationConfiguration
registrerer bla enBearerTokenClientHttpRequestInterceptor
Denne interceptoren hekter da på token fra TokenValidationContext
på utgående forespørsler. Når tokenX brukes kan vi ikke gjøre det, det trengs en egen interceptor eller tilsvarende som gjør vekslingen og hekter på resultatet av denne i en header istedet. BearerTokenClientHttpRequestInterceptor
kan altså kke være en interceptor på tokenX-klienter, den kommer i veien. Dette resulterer i tuklete initialiseringskode for slike klienter, se f.eks her. Hadde det vært en ide å tilby et felt i @EnableJwtTokenValidationConfiguration
som styrer om BearerTokenClientHttpRequestInterceptor
skal registreres eller ikke ?
f.eks @EnableJwtTokenValidationConfiguration(registerDefaultBearerInterceptor=false)
elns?
Dersom metadata-endepunktet er utilgjengelig under oppstart av applikasjonen så lastes ikke Spring-konfigurasjonen og den feiler med følgende exception: org.springframework.context.ApplicationContextException: Unable to start web server
.
Dette skjer dersom man bruker følgende autokonfigurasjon med følgende annotering: @EnableJwtTokenValidation
.
Selv om dette kanskje er et sjeldent scenario i prod så kan det lett forekomme under integrasjonstesting dersom man bruker docker-compose og mock-idp container starter opp tregere enn applikasjonen som er under test.
Årsaken er følgende linje i IssuerConfiguration.java
som forutsetter at metadata-endepunktet er oppe:
return OIDCProviderMetadata.parse(resourceRetriever.retrieveResource(url).getContent());
Et fullstendig stacktrace følger under:
k9-infotrygd-feed | 2020-03-05 14:54:11.626 ERROR 6 --- [ main] o.s.boot.SpringApplication : Application run failed
k9-infotrygd-feed |
k9-infotrygd-feed | org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
k9-infotrygd-feed | at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:156) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at no.nav.k9.integrasjon.infotrygd.k9infotrygdfeed.K9InfotrygdFeedApplicationKt.main(K9InfotrygdFeedApplication.kt:13) ~[classes!/:0.0.1-SNAPSHOT]
k9-infotrygd-feed | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
k9-infotrygd-feed | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
k9-infotrygd-feed | at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
k9-infotrygd-feed | at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
k9-infotrygd-feed | at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[app.jar:0.0.1-SNAPSHOT]
k9-infotrygd-feed | at org.springframework.boot.loader.Launcher.launch(Launcher.java:109) ~[app.jar:0.0.1-SNAPSHOT]
k9-infotrygd-feed | at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[app.jar:0.0.1-SNAPSHOT]
k9-infotrygd-feed | at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:93) ~[app.jar:0.0.1-SNAPSHOT]
k9-infotrygd-feed | Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
k9-infotrygd-feed | at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:126) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.<init>(TomcatWebServer.java:88) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getTomcatWebServer(TomcatServletWebServerFactory.java:438) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:191) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:180) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:153) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | ... 17 common frames omitted
k9-infotrygd-feed | Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oidcTokenValidationFilterRegistrationBean' defined in class path resource [no/nav/security/token/support/spring/EnableJwtTokenValidationConfiguration.class]: Unsatisfied dependency expressed through method 'oidcTokenValidationFilterRegistrationBean' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'tokenValidationFilter' defined in class path resource [no/nav/security/token/support/spring/EnableJwtTokenValidationConfiguration.class]: Unsatisfied dependency expressed through method 'tokenValidationFilter' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'multiIssuerConfiguration' defined in class path resource [no/nav/security/token/support/spring/EnableJwtTokenValidationConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [no.nav.security.token.support.core.configuration.MultiIssuerConfiguration]: Factory method 'multiIssuerConfiguration' threw exception; nested exception is no.nav.security.token.support.core.exceptions.MetaDataNotAvailableException: could not retrieve metadata from url: http://vtp:8060/rest/isso/oauth2/.well-known/openid-configuration. received exception java.net.ConnectException: Connection refused (Connection refused)
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:539) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:211) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.ServletContextInitializerBeans.getOrderedBeansOfType(ServletContextInitializerBeans.java:202) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.ServletContextInitializerBeans.addServletContextInitializerBeans(ServletContextInitializerBeans.java:96) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.ServletContextInitializerBeans.<init>(ServletContextInitializerBeans.java:85) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getServletContextInitializerBeans(ServletWebServerApplicationContext.java:253) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.selfInitialize(ServletWebServerApplicationContext.java:227) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.springframework.boot.web.embedded.tomcat.TomcatStarter.onStartup(TomcatStarter.java:53) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5135) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
k9-infotrygd-feed | at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) ~[na:na]
k9-infotrygd-feed | at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:841) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1384) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1374) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
k9-infotrygd-feed | at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140) ~[na:na]
k9-infotrygd-feed | at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:909) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.core.StandardService.startInternal(StandardService.java:421) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.apache.catalina.startup.Tomcat.start(Tomcat.java:467) ~[tomcat-embed-core-9.0.31.jar!/:9.0.31]
k9-infotrygd-feed | at org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize(TomcatWebServer.java:107) ~[spring-boot-2.3.0.M2.jar!/:2.3.0.M2]
k9-infotrygd-feed | ... 22 common frames omitted
k9-infotrygd-feed | Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'tokenValidationFilter' defined in class path resource [no/nav/security/token/support/spring/EnableJwtTokenValidationConfiguration.class]: Unsatisfied dependency expressed through method 'tokenValidationFilter' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'multiIssuerConfiguration' defined in class path resource [no/nav/security/token/support/spring/EnableJwtTokenValidationConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [no.nav.security.token.support.core.configuration.MultiIssuerConfiguration]: Factory method 'multiIssuerConfiguration' threw exception; nested exception is no.nav.security.token.support.core.exceptions.MetaDataNotAvailableException: could not retrieve metadata from url: http://vtp:8060/rest/isso/oauth2/.well-known/openid-configuration. received exception java.net.ConnectException: Connection refused (Connection refused)
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:539) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1287) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | ... 62 common frames omitted
k9-infotrygd-feed | Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'multiIssuerConfiguration' defined in class path resource [no/nav/security/token/support/spring/EnableJwtTokenValidationConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [no.nav.security.token.support.core.configuration.MultiIssuerConfiguration]: Factory method 'multiIssuerConfiguration' threw exception; nested exception is no.nav.security.token.support.core.exceptions.MetaDataNotAvailableException: could not retrieve metadata from url: http://vtp:8060/rest/isso/oauth2/.well-known/openid-configuration. received exception java.net.ConnectException: Connection refused (Connection refused)
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1287) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | ... 76 common frames omitted
k9-infotrygd-feed | Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [no.nav.security.token.support.core.configuration.MultiIssuerConfiguration]: Factory method 'multiIssuerConfiguration' threw exception; nested exception is no.nav.security.token.support.core.exceptions.MetaDataNotAvailableException: could not retrieve metadata from url: http://vtp:8060/rest/isso/oauth2/.well-known/openid-configuration. received exception java.net.ConnectException: Connection refused (Connection refused)
k9-infotrygd-feed | at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | ... 90 common frames omitted
k9-infotrygd-feed | Caused by: no.nav.security.token.support.core.exceptions.MetaDataNotAvailableException: could not retrieve metadata from url: http://vtp:8060/rest/isso/oauth2/.well-known/openid-configuration. received exception java.net.ConnectException: Connection refused (Connection refused)
k9-infotrygd-feed | at no.nav.security.token.support.core.configuration.IssuerConfiguration.getProviderMetadata(IssuerConfiguration.java:121) ~[token-validation-core-1.1.4.jar!/:na]
k9-infotrygd-feed | at no.nav.security.token.support.core.configuration.IssuerConfiguration.<init>(IssuerConfiguration.java:41) ~[token-validation-core-1.1.4.jar!/:na]
k9-infotrygd-feed | at no.nav.security.token.support.core.configuration.IssuerConfiguration.<init>(IssuerConfiguration.java:32) ~[token-validation-core-1.1.4.jar!/:na]
k9-infotrygd-feed | at no.nav.security.token.support.core.configuration.MultiIssuerConfiguration.createIssuerConfiguration(MultiIssuerConfiguration.java:65) ~[token-validation-core-1.1.4.jar!/:na]
k9-infotrygd-feed | at no.nav.security.token.support.core.configuration.MultiIssuerConfiguration.loadIssuerConfigurations(MultiIssuerConfiguration.java:52) ~[token-validation-core-1.1.4.jar!/:na]
k9-infotrygd-feed | at no.nav.security.token.support.core.configuration.MultiIssuerConfiguration.<init>(MultiIssuerConfiguration.java:25) ~[token-validation-core-1.1.4.jar!/:na]
k9-infotrygd-feed | at no.nav.security.token.support.spring.EnableJwtTokenValidationConfiguration.multiIssuerConfiguration(EnableJwtTokenValidationConfiguration.java:77) ~[token-validation-spring-1.1.4.jar!/:na]
k9-infotrygd-feed | at no.nav.security.token.support.spring.EnableJwtTokenValidationConfiguration$$EnhancerBySpringCGLIB$$ab702c21.CGLIB$multiIssuerConfiguration$4(<generated>) ~[token-validation-spring-1.1.4.jar!/:na]
k9-infotrygd-feed | at no.nav.security.token.support.spring.EnableJwtTokenValidationConfiguration$$EnhancerBySpringCGLIB$$ab702c21$$FastClassBySpringCGLIB$$3088d512.invoke(<generated>) ~[token-validation-spring-1.1.4.jar!/:na]
k9-infotrygd-feed | at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) ~[spring-context-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | at no.nav.security.token.support.spring.EnableJwtTokenValidationConfiguration$$EnhancerBySpringCGLIB$$ab702c21.multiIssuerConfiguration(<generated>) ~[token-validation-spring-1.1.4.jar!/:na]
k9-infotrygd-feed | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
k9-infotrygd-feed | at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
k9-infotrygd-feed | at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
k9-infotrygd-feed | at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
k9-infotrygd-feed | at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.3.RELEASE.jar!/:5.2.3.RELEASE]
k9-infotrygd-feed | ... 91 common frames omitted
k9-infotrygd-feed | Caused by: java.net.ConnectException: Connection refused (Connection refused)
k9-infotrygd-feed | at java.base/java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:na]
k9-infotrygd-feed | at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:399) ~[na:na]
k9-infotrygd-feed | at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:242) ~[na:na]
k9-infotrygd-feed | at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:224) ~[na:na]
k9-infotrygd-feed | at java.base/java.net.Socket.connect(Socket.java:609) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:177) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.http.HttpClient.<init>(HttpClient.java:242) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:341) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:362) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1248) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1187) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1081) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1015) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1587) ~[na:na]
k9-infotrygd-feed | at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1515) ~[na:na]
k9-infotrygd-feed | at com.nimbusds.jose.util.DefaultResourceRetriever.getInputStream(DefaultResourceRetriever.java:249) ~[nimbus-jose-jwt-8.9.jar!/:8.9]
k9-infotrygd-feed | at com.nimbusds.jose.util.DefaultResourceRetriever.retrieveResource(DefaultResourceRetriever.java:201) ~[nimbus-jose-jwt-8.9.jar!/:8.9]
k9-infotrygd-feed | at no.nav.security.token.support.core.configuration.IssuerConfiguration.getProviderMetadata(IssuerConfiguration.java:119) ~[token-validation-core-1.1.4.jar!/:na]
k9-infotrygd-feed | ... 107 common frames omitted
When building project: terminal sends warnings in project: token-validation-ktor
about deprecated JwtTokenGenerator. This will probably need some more investigation, and can depend on the JAVA update.
Det ser ut til å være en regresjon i siste versjon av token-support, i forhold til gamle 0.2.X-versjoner. Jeg holder på å løfte en Spring Boot app hos oss fra 0.2.X til seneste 1.1.4. I appen vår er det flere Spring-controllere som benytter:
@ProtectedWithClaims(issuer = "selvbetjening", combineWithOr = true, claimMap = {"acr=Level3", "acr=Level4"})
Alle disse brekker med ny token-support pga. en intern IllegalStateException
som skjer i JwtTokenAnnotationHandler
(fører til 401/unauthorized ut, selv om token har nødvendig claim). Der bruker man Collectors.toMap(..)
for å samle alle annotation-claims nederst i klassen, men denne metoden vil feile dersom samme nøkkel opptrer flere ganger. Det er tilfellet for oss, da vi enten krever acr=Level3
eller acr=Level4
. Dersom man ved bygging av map vil håndtere aggregering av verdier for samme nøkkel, eller "siste verdi for samme nøkkel vinner-strategi", etc, så må man plugge inn slik logikk selv, som en merge-function.
Jeg ser ikke helt poenget med å gjøre om til map før sjekking av claims i den koden, så jeg kommer til å foreslår endringer i en pr, med tilhørende test for JwtTokenAnnotationHandler
.
token-client-core drar inn alltid kotlin-stdlib-jdk8 med.
Er den dependencien nødvendig?
In order to have multiple issuers when using oidc-test-support
in dev/local mode you have to configure the same metadata/jwks on all issuers as the FileResourceRetriever
only supports one set of files. The TokenGeneratorController
also only issues tokens from a single issuer.
When protecting 2 endpoints with different issuers, e.g. @ProtectedWithClaims(issuer="abc")
and @ProtectedWithClaims(issuer="xyz")
, in local mode you could get a 401 on issuer xyz
as only a token for issuer abc
has been found and vice versa. This is due to that the issuers are essentially the same.
One solution is to allow to specify file:// in the discoveryurl and let the FileResourceRetriever also support "live" providers over HTTP.
From @janolaveide:
Som du sikkert har lest er RestTemplate i maintenance mode, og det er WebClient som er framtiden, både for blocking og non-blocking.
Den har en litt annen mekanisme for ClientHttpRequestInterceptor, nemlig ExchangeFilterFunction.
Så da bør vel både BearerTokenClientHttpRequestInterceptor og JwtTokenHandlerInterceptor få en reaktiv variant (i et eget repo, token-validation-spring-reactive ?)
Se https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-client-filter
Biblioteket baserer seg på at det kun er én cookie med navnet man konfigurerer opp. Dette fungerer til de fleste formål, men "in the wild" har vi oppdaget at mange interne brukere har to cookies som begge heter ID_token, men med forskjellige domains (adeo.no og nais.adeo.no). Disse kommer fra OpenAM. Alle kall fra disse brukerne feiler mot vår backend. Selv om vi faktisk kun trenger Azure-validering i det aktuelle endepunktet.
Ideell oppførsel sett fra min side, ville vært om biblioteket validerer alle tokens med det gitte navnet, og bare velger et token å gå videre med hvis det er flere gyldige.
Do we use sonar for scanning code anymore?
Dont we use codeql?
Jeg har såvidt begynt å forberede meg til oppgradering til versjon >= 3.0.0 av spring-boot-starter-parent. I den forbindelse la jeg inn token-validation-spring-test i pom.xml fila mi. Konsekvensen ble at loggeformatet i apploggen (Kibana/logs.adeo.no) til appen ble feil: Feltet level
(loglevel) og component
(navnet på den loggende klassen) fikk ingen verdi, message
inneholdt både level og timestamp, og jeg tror jeg mistet exceptions/stacktraces. Jeg tenkte jeg skulle tipse om dette i tilfelle biblioteket bundler noe loggkonfig som det ikke trenger å gjøre. Det var litt skummelt, for vi kjørte i en måned i prod før jeg oppdaget dette.
Må understreke at det kan godt hende at det var min egen feil fordi jeg ikke har brukt biblioteket riktig ennå. F.eks. har jeg ikke brukt test scope i pom, og har hatt den i pom samtidig med den gamle token-validation-test-support. Fiksen min, hvis dette er aktuelt å se nærmere på: https://github.com/navikt/rekrutteringsbistand-kandidat-api/pull/206
Multiple versions of nimbus-jose-jwt
on classpath may lead to exceptions such as:
NoSuchMethodError: com.nimbusds.jose.jwk.JWKSet.toJSONObject()Lnet/minidev/json/JSONObject;
Read more:
https://connect2id.com/blog/nimbus-jose-jwt-9
Figure out what can be done to avoid this and remove dependency on stuff from net.minidev:json-smart etc
More details on related exceptions:
https://nav-it.slack.com/archives/C60FFACN5/p1599489125306800
Uten istio er det vanskelig å sikre seg mot at kun spesifikke applikasjoner kaller tjenestene man lager. I familie har vi implementert en interceptor som sjekker om azp i tokenet finnes i en liste av ACCEPTED_CLIENTS(client id'er). Jeg foreslår å legge til denne logikken i dette biblioteket slik at alle kan definere en liste av ACCEPTED_CLIENTS per registration slik at endepunktet kun tillater trafikk fra spesifikke apper.
Vi har kall fra eksterne med autentiseringstoken som ikke er jwt. Disse er ekskludert fra JWT Token validation (forsøkt både med @unprotected og ignore på annotasjon i mainmetode). Likevel ser vi følgende warning i loggene: «Received exception when attempting to extract and parse token from Authorization header» (pga missing dot delimiters).
Spring boot > 2.4 bruker "for ny" versjon av com.nimbusds:nimbus-jose-jwt, version 9.1.3
Ved validering av token oppstår en NSME, men denne logges aldri, alt man ser er
found 1 tokens on request, number of validated tokens is 0
Løsninger er å nedgradere denne versjonen på denne måten
<nimbus-jose-jwt.version>8.20</nimbus-jose-jwt.version>
men token support burde logge NSME slik at dette ble enklere å feilsøke for andre som har samme problemet.
When processing OAuth tokens, they are attempted validated as OIDC, resulting in a BadJWTException being thrown over missing sub claims.
Får stacktraces á la:
Caused by: no.nav.security.oidc.exceptions.MetaDataNotAvailableException: java.net.ConnectException: Connection refused: connect
at no.nav.security.oidc.configuration.IssuerConfiguration.getProviderMetadata(IssuerConfiguration.java:114)
at no.nav.security.oidc.configuration.IssuerConfiguration.<init>(IssuerConfiguration.java:40)
...
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
...
når Spring Boot-properties har feil i issuer-discovery-URL-ene. F.eks. følgende konfigurasjon:
no.nav.security.oidc.issuer.localhost.discoveryurl=http://no-such-host/metadata
no.nav.security.oidc.issuer.localhost.acceptedaudience=aud-localhost
Her bør unntaket ConnectException
fanges opp og dekoreres med detaljer om i det minste vertsnavnet, gjerne også hele URL-en og/eller annen aktuell informasjon om utstederen.
Når en metode ikke er annotert foreslår jeg at dette burde håndteres som en InternalServerError og ikke Uauthorized. Da det er feil på serverens konfigurasjon og ikke at brukeren ikke er autentisert. Jeg tenker denne også burde logges som error og ikke debug
Det gjelder OIDCTokenControllerHandlerInterceptor.preHandle (linje 104):
logger.debug("method " + handlerMethod + " not marked, access denied (returning NOT_IMPLEMENTED)"); throw new OIDCUnauthorizedException("Server misconfigured - controller/method [" + handlerMethod.getBean().getClass().getName() + "." + handlerMethod.getMethod().getName() + "] not annotated @Unprotected, @Protected or added to ignore list");
Jeg er redd en slik feil ikke vil bli fanget opp om den havner i produksjon. Da 401 ofte er implementert til å trigge en ny pålogging fra frontend.
Om en er redd for at en slik endring kan brekke andre prosjekter så kanskje man kunne kastet en underklasse av OIDCUnauthorizedException slik at gamle prosjekter fortsatt håndterer den som før, mens nye prosjekter har mulighet til å håndtere akkurat denne spesielt.
Iht https://datatracker.ietf.org/doc/html/rfc6750#section-3.1 skal feil scope gi 403 og ikke 401.
Burde Lombok (i token-client-spring) ha hatt scope provided
? Fordi den ikke trengs runtime?
With the introduction of @ConstructorBinding in Spring Boot 2.2.0, they introduced a behaviour by accident:
"if a top-level configuration properties was using constructor binding, any element that's part of the constructor (including classes that are defined outside of the top-level object) was also using constructor binding."
This behaviour suited our purpose well as to not have Spring dependencies in our core modules where the data binding classes reside. However in version 2.2.1 the Spring team corrected this behaviour - see this issue: spring-projects/spring-boot#18919 (comment).
If you are using Spring 2.2.1 on the current version of token-support, the application context will fail to load due to the change in @ConstructorBinding behaviour.
We have chosen to wait for this issue - spring-projects/spring-boot#18935 - before bumping Spring version.
Når vi tar i bruk accesstokens utstedt av AzureAD (client credentials grant) for server-til-server-integrasjon får vi behov for å kunne sjekke dynamiske claims med annotasjonen "ProtectedWithClaims" for å sikre at kun spesifiserte apper har tilgang til api'et. Kan dere vurdere om dette er noe dere ønsker å støtte i biblioteket?
Se gjerne diskusjon på slack: https://nav-it.slack.com/archives/CFTR8QE3T/p1549446169077300
In ClientAuthenticationProperties
add something along the lines of:
private static RSAKey loadKey(String clientPrivateKey){
if(clientPrivateKey != null){
if (clientPrivateKey.startsWith("{")){
return JwkFactory.fromJson(clientPrivateKey);
} else {
return JwkFactory.fromJsonFile(clientPrivateKey);
}
}
return null;
}
Har dere mulighet til å lage en versjon på java 21?
Hei!
Hadde det vært en idè å legge inn retry når man utsteder tokens, for å unngå eks feilet "Connection Reset".
Burde vel også vurdere hvilke andre feil som kan være interessante å håndtere, samt hvordan, kanskje retry en gang er tilstrekkelig eller burde man ha exponential backoff? Tror ikke vi trenger exponential backoff.
https://nav-it.slack.com/archives/C5KUST8N6/p1629368229194400
Semver etc...
Vurder gjerne å fjerne stacktrace på loggen om at bruker sin token er blitt invalid.
Dette er vanlig flyt når bruker enten ikke har logget seg på eller når token er utløpt og jeg ser ikke behovet for å ha med stacktrace. Stacktracen får meg ofte til å tro at det er skjedd noe galt når jeg utvikler lokalt.
Dette er ikke noe kritisk eller viktig, kun et irritasjonsmoment :)
12:18:35 [xec-2] INFO OIDCTokenValidationFilter : Invalid token for issuer [azuread, expires at Fri Apr 26 17:47:25 CEST 2019] no.nav.security.oidc.exceptions.OIDCTokenValidatorException: Token validation failed at no.nav.security.oidc.validation.OIDCTokenValidator.assertValidToken(OIDCTokenValidator.java:49) at no.nav.security.oidc.validation.OIDCTokenValidator.assertValidToken(OIDCTokenValidator.java:40)
Today token-support only supports issuers on OpenID Provider (OP) configuration: /.well-known/openid-configuration
For applications using issuers as Maskinporten: /.well-known/oauth-authorization-server
, cant use token-support as it s no.1 validator for jwt tokens.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.