Code Monkey home page Code Monkey logo

waffle's Introduction

WAFFLE - Windows Authentication Framework

Java CI DotNET CI Coverity Scan Status Coverage Status Sonar Coverage Status Coveralls Maven central releases MIT Project Stats Github All Releases Quality Gate Status

waffle

WAFFLE is a native Windows Authentication Framework consisting of two C# and Java libraries that perform functions related to Windows authentication, supporting Negotiate, NTLM and Kerberos. Waffle also includes libraries that enable drop-in Windows Single Sign On for popular Java web servers, when running on Windows. While Waffle makes it ridiculously easy to do Windows Authentication in Java, on Windows, Waffle does not work on *nix(UNIX-like).

Unlike many other implementations Waffle on Windows does not require any server-side Kerberos keytab setup, it's a drop-in solution. You can see it in action in this slightly blurry video produced for TeamShatter.com.

Sites

Essentials

Documentation

There're several semi-independent parts to Waffle. Choose the appropriate HowTo.

  • Simple native interfaces in C# and Java to do all things Windows authentication. Useful if you're building a custom client that requires Windows authentication. See Getting Started with WAFFLE API
  • A generic Servlet Negotiate (NTLM and Kerberos) Security Filter that can be used with many web servers, including Tomcat, Jetty and WebSphere. See HowTo.
  • A Tomcat Negotiate (NTLM and Kerberos) Authenticator Valve, built for the Tomcat Web Container. See HowTo.
  • A Tomcat Single Sign-On + Form Authentication Mixed Valve, built for the Tomcat Web Container and allowing users to choose whether to do form authentication (a username and password sent to the server from a form) or Windows SSO (NTLM or Kerberos). See HowTo.
  • A Spring-Security Negotiate (NTLM and Kerberos) Filter. See HowTo.
  • A Spring-Security Windows Authentication Manager. See HowTo.
  • A JAAS Login Module, useful when extending a custom Java client that already implements JAAS to support Windows SSO. See HowTo.
  • A WildFly Security Domain implementation, offering support for local Windows and Active Directory users authentication when deploying web apps on WildFly servers. See HowTo.

Waffle was created and is sponsored by Application Security Inc.. For a long story, read the Project History. Also, feel free to use this PowerPoint presentation from NYJavaSIG to talk about Waffle.

Features

  • Account lookup locally and in Active Directory via Win32 API with zero configuration.
  • Enumerating Active Directory domains and domain information.
  • Returns computer domain / workgroup join information.
  • Supports logon for local and domain users returning consistent fully qualified names, identity (SIDs), local and domain groups, including nested.
  • Supports all functions required for implementing server-side single-signon with Negotiate and NTLM and various implementations for Java web servers.
  • Supports Windows Identity impersonation.
  • Includes a Windows Installer Merge Module for distribution of C# binaries.

How do I resolve JNA NoClassDefFound errors?

WAFFLE uses the latest version of JNA, which may conflict with other dependencies your project (or its parent) includes. If you experience issues with NoClassDefFound errors for JNA artifacts, consider one or more of the following steps to resolve the conflict:

  • Listing WAFFLE earlier (or first) in your dependency list
  • Specifying the most recent version of JNA as a dependency
  • If you are using a parent (e.g., Spring Boot) that includes JNA as a dependency, override the jna.version property

Demos

WAFFLE packages serveral demos. When building from the source, you can use mvn cargo:run to bring any of the demos up. See further README documentation in each demo (and what doesn't quite work). Additionally demos are documented in various states in documentation. This area does need some user help so feel free to contribute.

Related and Similar Products

Contributing

License and Copyright

Copyright (c) Application Security Inc., 2010-2020 and Contributors.

This project is licensed under the MIT License.

Project maintained by Daniel Doubrovkine & Jeremy Landis.

waffle's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

waffle's Issues

Embedded Jetty sample doesn't run

Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/ServletContainerInitializer
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClassCond(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$000(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at org.apache.jasper.EmbeddedServletOptions.<init>(EmbeddedServletOptions.java:697)
    at org.apache.jasper.servlet.JspServlet.init(JspServlet.java:158)
    at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:477)
    at org.eclipse.jetty.servlet.ServletHolder.doStart(ServletHolder.java:293)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
    at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:739)
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:254)
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1238)
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:683)
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:480)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
    at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:95)
    at org.eclipse.jetty.server.Server.doStart(Server.java:275)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:64)
    at waffle.jetty.StartEmbeddedJetty.main(StartEmbeddedJetty.java:69)
Caused by: java.lang.ClassNotFoundException: javax.servlet.ServletContainerInitializer
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 27 more

Upgrading the dependency to servlet 3.x in .classpath (<classpathentry kind="lib" path="/thirdparty/_lib/jar/javax.servlet/3.0.1/javax.servlet-api-3.0.1.jar"/> ), has its own new problems. The server runs, but there's an error when trying to hit localhost:8080:

javax.servlet.ServletContext.getJspConfigDescriptor()Ljavax/servlet/descriptor/JspConfigDescriptor;

Formatting Change Request

I want to save this until very last before releasing 1.7. I am using sonar/findbugs and have pmd/checkstyles also configured for use. When running various checks, some things jump out that need fixed. Of this is the need to stop using tab characters. It seems I've been fighting a never ending battle to get this project consistently formatted. The main formatting is tab based but there are still a number of locations space based and I've been well aware for a long time that tabs should not be used for various reasons. This leads me to wanting to propose, if acceptable, switching to spaces rather than tabs. I generally use a 4 space indentation instead of tabs. I've seen other projects such as mybatis use 2 character spacing. Are you interested in making this change and if so what is the spacing preference?

If you take a look at the POMs currently, you will see they are all actually using 4 spaces in lieu of tabs now. Some of the shiro modules are doing the same.

Now by making this change, it itself would be a single commit as it will have to be accepted that the formatting did work as expected. Once the formatting is completed, I would then turn on a formatter plugin that I have already in the POMs. This will further ensure, regardless of IDE, that our formatting is forced to be expected regardless of person submitting code changes. That way formatting becomes something we don't need worry ourselves about going forward.

Releasing 1.7

@dblock I started the release process for 1.7 but seem to be having some issues. The second step 'mvn release:prepare' seems to just hang once it gets to the git commands. I let it sit like that for well over an hour. Maybe you can try to run through the steps to release out to central?

The token supplied to the function is invalid

There appears to be a bug introduced in last week or so to the project affecting waffle-test and tomcat modules unit tests where 'the token supplied to the function is invalid'. This is a marker so that we don't release until this has been resolved. Sufficient logging exists around this to log the condition. More research is required to resolve this.

Waffle 1.7.x adaption rate

Nexus is starting to show better adoption rates on waffle 1.7.x so wanted to highlight here. I'll provide additional notes on this 'info' tab for a bit. I'm sort of using this to guage an appropriate time to drop legacy support.

Using unique ip in checks over last month, the percentage of adoption rate over other versions.

waffle-jetty 94%
waffle-jna 30% - Version 1.5 still leads here followed by 1.6 then 1.7*
waffle-shiro 100%
waffle-spring2 90%
waffle-spring3 32%. 1.6 still leads but this is now ahead of 1.5
waffle-spring4 100% (new for this version)
waffle-tests - 50% tie with version 1.6
waffle-tomcat5 100%
waffle-tomcat6 92%
waffle-tomcat7 44% tied with version 1.6
waffle-tomcat8 100% (new for this version)

Full complete release of demos to central are also seeing an uptick so that was a good move. Overall 346 downloads of waffle-jna for the month followed by spring 3 then tomcat 7. It significantly drops off after that point.

  • waffle-jna 1.7.1 version does not appear to have been that important as it isn't being picked up. Maybe this will change next month.

Build all fails first time on ant clean

  BUILD FAILED
  C:\Users\dblock\source\waffle\dblock\Source\JNA\build.xml:28: The following error occurred while executing this line:
  C:\Users\dblock\source\waffle\dblock\Source\JNA\build.xml:4: The following error occurred while executing this line:
  C:\Users\dblock\source\waffle\dblock\Source\JNA\waffle-jna\build.xml:5: The following error occurred while executing
  this line:
  C:\Users\dblock\source\waffle\dblock\Source\JNA\build\build.xml:6: Missing product.version

  Total time: 1 second
C:\Users\dblock\source\waffle\dblock\Waffle.proj(39,5): error MSB3073: The command "ant clean" exited with code 1.
Done Building Project "C:\Users\dblock\source\waffle\dblock\Waffle.proj" (all target(s)) -- FAILED.


Build FAILED.

"C:\Users\dblock\source\waffle\dblock\Waffle.proj" (all target) (1) ->
(clean target) ->
  C:\Users\dblock\source\waffle\dblock\Waffle.proj(39,5): error MSB3073: The command "ant clean" exited with code 1.

    0 Warning(s)
    1 Error(s)

Help to delegate from IIS to Waffle

Hi all,

I use waffle with tomcat 6 to authenticate the user.
The configuration is simple. I deploy waffle only in one webapps and I use the filter waffle.servlet.NegotiateSecurityFilter. Eveything is ok.

We have an other server on IIS. This server use the kerberos protocol to authenticate the user.

Now the server IIS have to call tomcat by transferring the kerberos ticket, but we are always authenticated ยซ ANONYMOUS LOGON ยป on tomcat.

Have you some ideas to configure waffle in order to get the good user send by IIS ?

Thank for your help.

gh-pages update needed

git hub pages is significantly out of date. Last included 1.5 release. I'd like to rework this into using the maven site page and hopefully include the look and feel unless it is ok to just go with the bookstrap style. The verbiage would all be present and all downloads would be shown. To see this suggestion, please take a look at here. This is a quick and easy thing to do which I can get up pretty quickly.

The only thing that might hold up how fast this gets completed would be any issues with multi maven project which in general seem to be tricky.

Coverall Coverage Status

Coveralls plugin was rewritten recently to handle multi module projects correctly. This now partially works with waffle. In order to run this at the moment, I had to turn off the builds for tomcat 7 and 8. With those on, it produces a coveralls error ArrayIndexOutOfRange. Ignoring those at the moment, you can check my page to see that we are now getting coverage numbers. I'll keep working at this as this is good information to have and likely the issue in tomcat 7/8 should jump out at me after some review. Once I can get those included, I need to look at best way to apply this to overall codebase as it currently requires a token that shouldn't be shared. So hopefully very soon, the coverage numbers will start appearing on the main library here.

https://github.com/hazendaz/waffle

Travis-ci

It would be nice to turn on travis-ci so all pull requests / pushes get built verifying at least the code compiles without issue so we don't waste time applying broken changes. In the past, there were a number of times when fully mavenizing the project that issues became present. This should resolve that at least on the java portion. It may be possible to have it build everything but windows isn't supported with travis-ci currently. Additionally, it is required to skip tests in order to build due to dependency on native windows. I've been running this for a while now in my forked repo.

As to setup, it is pretty trivial to setup. See https://travis-ci.org/ for details. Once setup on this project, emails can be generated out with status of builds.

how to set public urls on web.xml?

I've got a SecurityFilter set to /* pattern and I need to set the /public/* as a public path. How could it be done?

I can't use the valve approach with security-constraints.

I am following the example given with the waffle-filter project.

<filter>
        <filter-name>SecurityFilter</filter-name>
        <filter-class>waffle.servlet.NegotiateSecurityFilter</filter-class>
        <init-param>
            <param-name>principalFormat</param-name>
            <param-value>fqn</param-value>
        </init-param>
        <init-param>
            <param-name>roleFormat</param-name>
            <param-value>both</param-value>
        </init-param>
        <init-param>
            <param-name>allowGuestLogin</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>securityFilterProviders</param-name>
            <param-value>waffle.servlet.spi.NegotiateSecurityFilterProvider
waffle.servlet.spi.BasicSecurityFilterProvider</param-value>
        </init-param>
        <init-param>
            <param-name>waffle.servlet.spi.NegotiateSecurityFilterProvider/protocols</param-name>
            <param-value>NTLM
Negotiate</param-value>
        </init-param>
        <init-param>
            <param-name>waffle.servlet.spi.BasicSecurityFilterProvider/realm</param-name>
            <param-value>myrealm</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>SecurityFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Maven Enhancement

Waffle-pom and Waffle-demo-parent locations cause unnecessary confusion. Per prior fixes noted around the waffle demo parent this became somewhat obvious. I have already removed the waffle-pom layer by combining the multi module into waffle-parent (no pull request yet). This task will additionally involve renaming waffle-demo-parent to waffle-demo and submodule waffle-demo-parent there which will make it much more clear and allow file directory location to mirror what is pulled into IDE of choice.

This means no pom will be under JNA and that pom will be combined with waffle-parent. Waffle-demo-parent folder will be renamed as waffle-demo. The pom will be moved into subproject waffle-demo-parent.

Waiting on #101 before finishing this one off. Hopefully for waffle 1.7 release.

tomcat 5 EOL & tomcat 8

https://tomcat.apache.org/tomcat-55-eol.html

Tomcat 5 was end of life quite some time ago. I think it might be time to drop official support in upcoming releases for tomcat 5.

Tomcat 8 is out but still in beta. However, it is being run over at apache on the jiras so production ready. I have taken a copy of tomcat 7 version of waffle and started getting it built out for tomcat 8. Not sure how long this will take me to finalize. I do have it building without errors but need to test :)

Waffle 1.8

Tasks for waffle 1.8

  1. Create branch called '1.7.x' as soon as 1.7 is released for one year support of 1.7.x. Created 1/3/2015
  2. Remove Tomcat 5 support. Completed 1/3/2015
  3. Remove Spring 2 support. Completed 1/3/2015
  4. Remove Deprecated Base64 as waffle uses guava now. Resolved 1.7.1
  5. Perform Eclipse source cleanup against entire library (two pass, no sorting first round). Completed 7/12/2015 - sorting and some formatting skipped.
  6. Review moving to java 7. Completed 6/14/2015
  7. Review moving to Servlet 3.0.1. Deferred as we support tomcat 6 which is servlet 2.5.
  8. Review slf4j/logback binding issues when running waffle at container layer. See https://github.com/grgrzybek/tomcat-slf4j-logback on how to approach this unless better solution is found. Moved to separate issue.
  9. Review possibility for any new integrations. Moved to separate issue.
  10. Make official spring security 4 release. Previously we used earlier version that was not available in central. Completed 4/11/2015

No support for authorization in service provider

This issue is created as something to refer to for pull request: #174

Once the authenticaiton provider(e.g the Active Directory) has authenticated the principal, waffle
currently assumes that the principal is authorized to use the service that the service provider(e.g service/application) that is using waffle to authenticate towards AD. This may not be the case. The principal may very well be in the Active Directory but not be authorized to use the service that the current service provider provides.

Can log authenticated user in Tomcat using NegotiateSecurityFilter

There are a couple of objects in the session that could be logged (but not remote user, it is only available in the wrapped request), if they exposed a toString method. It would nice to have toString method on WindowsPrincipal, so that the authenticated user could be logged with x-S(waffle.servlet.NegotiateSecurityFilter.PRINCIPAL) using the ExtendedAccessLogValve or %{waffle.servlet.NegotiateSecurityFilter.PRINCIPAL}s using the AccessLogValve.
#136

Exception stack trace on invalid credentials

The issue has been confirmed as a regression in 1.7. See [1] for complete discussion around the issue. Briefly: one get exception "com.sun.jna.platform.win32.Win32Exception: Logon failure: unknown user name or bad password." under Firefox when the host is not on the list of trusted URIs and one submits invalid credentials on the prompt. Previous version caused a reauthentication challenge. It has to be noted that my filter def contains both Negotiate and Basic providers enabled. The issue is caused by unchecked runtime excpetion thrown by inner class. See discussion [1] for more details and proposed workarounds.

[1] https://groups.google.com/forum/#!topic/waffle-users/066-7l7tg8I

Sonar Cleanup (Ongoing Effort)

I've been running sonar scans on this project for a little while now. I've been cleaning things as I can. I wanted to put this chore out here as a note about overall code cleanup. By ensuring we follow sonar with findbugs, we can lower overall cost of development time by removing known issues from the codebase.

Current outstanding issues

Blocker - 0
Critical - 2
Major - 439
Minor - 142
Info - 3
Technical Debt: 30 days

Of this, 90 in minor are due to using tabs rather than spaces. By far the largest issue is field naming convention issues. The _ on field names should not be used to start the fields. That one accounts for 174 of the major issues. Beyond that numbers drop off quite a bit. While it will not be possible to get to zero in all cases, I think we can get this below 100 give a few weeks.

Separate waffle-jni SSPI client into another JAR

The Waffle-JNI SSPI support is useful stand-alone for client applications.

Is there any interest in separating it into a separate jar that's emitted by the build? Or producing it as a secondary build target?

If you'd be willing to accept a patch to produce a waffle-jna-sspi-client.jar I'd be happy to create it. It'd be nice not to have to copy the relevant code, or bundle the whole large waffle-jna just for this support.

TestNegotiate depends on side-effect from another test

The WindowsAuthProviderImplUnitTests.TestNegotiate test does not complete successfully when run by itself.

It does pass if the following line of code is added to the top of the test:

Domain.GetComputerDomain();

Because this line of code is executed in previous tests in the same class, TestNegotiate appears to pass.

Note that my machine is connected to a domain. I am running the following version of Windows:

  • Microsoft Windows 8 Enterprise
  • 6.2.9200 N/A Build 9200

Java SPNego bug

I think there is a bug introduced in waffle 1.7.

AuthorizationHeader.isNtlmType1PostAuthorizationHeader() returns true for both SPNego message types (NegTokenInit or NegTokenArg), what causes call of auth.resetSecurityToken() inside NegotiateSecurityFilterProvider.doFilter().

Negotiation looses context when NegotiateSecurityFilterProvider receives NegTokenArg message.

This might be problem inside my code since I am implementing my own HttpServletRequest and HttpServletResponse interfaces, but it works in waffle 1.5 and 1.6.

WS

Spring single signon

Observation - the jars dont contain line numbers so its difficult to trace through, Also is it compiled for 1.6 only - is this a correct dependency.

how to set authentication failure url?

I use WAFFLE and it is great.
My issue: in a case where windows pops up a login window, and the user gives wrong credentials, or closes this window - I get a blank screen.
If the user enters wrong credentials, gets the popup login page again ,and then closes it - I get 401 error.

My question: Is there a way to configure authentication failure url (like Spring allows)?

Ohad

Java test suites run twice from ANT

The test suites combine all the other tests, and run twice.

test:
    [junit] Running waffle.apache.AllApacheTests
    [junit] Tests run: 20, Failures: 0, Errors: 0, Time elapsed: 2.294 sec
    [junit] Running waffle.apache.MixedAuthenticatorTests
    [junit] Tests run: 8, Failures: 0, Errors: 0, Time elapsed: 0.702 sec
    [junit] Running waffle.apache.NegotiateAuthenticatorTests
    [junit] Tests run: 8, Failures: 0, Errors: 0, Time elapsed: 0.843 sec
    [junit] Running waffle.apache.WindowsAccountTests
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.047 sec
    [junit] Running waffle.apache.WindowsRealmTests
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.062 sec

cc: @hazendaz

java.lang.UnsatisfiedLinkError: Can't obtain updateLastError method for class com.sun.jna.Native

Hi,

using waffle 6 und jna 4 I get the following stack:
Caused by: java.lang.UnsatisfiedLinkError: Can't obtain updateLastError method for class com.sun.jna.Native
at com.sun.jna.Native.initIDs(Native Method)
at com.sun.jna.Native.(Native.java:139)
at com.sun.jna.Pointer.(Pointer.java:42)
at com.sun.jna.platform.win32.WinNT$HANDLEByReference.(WinNT.java:1074)
at com.sun.jna.platform.win32.WinNT$HANDLEByReference.(WinNT.java:1070)
at waffle.windows.auth.impl.WindowsAuthProviderImpl.logonDomainUserEx(Unknown Source)
at waffle.windows.auth.impl.WindowsAuthProviderImpl.logonDomainUser(Unknown Source)

Apparently the updateLastError Method has been removed in JNA 4.0, so to me it appears as if waffle is incompatible with jna 4.

What to do ?

Stefan

Support basic authentication headers with ISO-1 encoding

Some browsers and also Java client send basic authentication headers with ISO-1 encoding. Other browser send it with UTF-8. Here is a patch to solve this. It try first an UTF-8 encoding and if this failing then use ISO-1 encoding.

-        final String usernamePassword = new String(authorizationHeader.getTokenBytes(), Charsets.UTF_8);
+        byte[] tokenBytes = authorizationHeader.getTokenBytes();
+        String usernamePassword = new String(tokenBytes, Charsets.UTF_8);
+        if( usernamePassword.contains( "\ufffd" ) ) { 
+            // if UTF-8 converting failing use ISO_8859_1
+            // Chrome use UTF-8, Java use ISO-1, IE and FF use ISO or platform default like CP1252
+            usernamePassword = new String(tokenBytes, Charsets.ISO_8859_1);
+        }

Rewrite all CodePlex FAQs into Markdown

CodePlex is having a lot of trouble. Extract FAQs into markdown.

How to retrieve/determine if group is netowrk/distribution?

I am using waffle and spring security to have a single-sign on solution. Everything works and I am able to allow access based on the user's belonging to network groups (created and maintained by IT staff here), but I am unable to get the distribution groups (emailing lists) that the user belongs to. This would be more helpful because emailing lists may be managed by non-IT staff and there is no extra steps/waiting times in modifying the groups memberships.

Any help would be appreciated.

Implement the appropriate SPI in Java to plug in JGSS easily

At the moment, Waffle is rather an alien solution in Java. It does not play at all with JGSS. One has the option to add service provider implementation to the Java system. This would mean that JGSS could use the SSPI backend transparently. There has been a preliminary patch to the JDK already but has been dropped.

See this patch: http://cr.openjdk.java.net/~weijun/6722928/webrev.00/jdk.patch
And the discussion on the security-dev mailing list:http://www.mail-archive.com/[email protected]/msg05287.html

Adapt that with Waffle and provide a fully integrating solution. It would make waffle superior to pure JGSS on Windows and a relief for every Java dev.

Completely mavenize build

I see that this project has made great strides towards maven but still uses quite a bit of ant. Is the vision to completely move to maven? I'm willing to help out in that area. If so, I'll start looking at doing so.

Document Manual Release Process

Document manual release process completely. Currently there is a bug in maven that prevents flat project structure from being released via the release plugin. The issue has roots as far back as 2008. While one of the original guys complaining heavily about the issue is now a main maven contributor, the issue still has not been completely resolved. So document manual process in case it never gets resolved.

How to unprotect a directory/path in an otherwise Waffle-protected application?

Waffle was properly protecting my entire app. However I need to have an unprotected area. My web.xml file now looks like below. However visiting any URL like
http://my.com/myapp/public/whatever
just returns a blank white screen. If I then go to a URL in my app that is not inside the public path (login required) then back to the original URL, it now works. How can I make Waffle honor my wishes to have some servlets, etc. not require a login?
Thanks!

<security-constraint>
    <display-name>Public Area</display-name>
    <web-resource-collection>
      <web-resource-name>Unprotected Area</web-resource-name>
      <url-pattern>/public/*</url-pattern>
    </web-resource-collection>
  </security-constraint>
  <security-role>
    <role-name>Everyone</role-name>
  </security-role>
  <security-constraint>
    <display-name>Waffle Security Constraint</display-name>
    <web-resource-collection>
      <web-resource-name>Protected Area</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>Everyone</role-name>
    </auth-constraint>
  </security-constraint>

response.setStatus(...) causes C# client to respond with invalid token

In waffle/servlet/spi/NegotiateSecurityFilterProvider.java, the following code snipet is the same in both 1.3 and 1.5, and the call to "response.setStatus(...)" in the code never works with C# client (only works with web browsers). It always causes the next token sent back from the C# client to be invalid (why?):
if (securityContext.getContinue() || ntlmPost) {
response.setHeader("Connection", "keep-alive");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); //<-------- setStatus( ) cause C# client to respond with invalid token -----
response.flushBuffer();
return null;
}

However, in 1.3, there was an additional package "waffle.apache" and I was using waffle/apache/NegotiateAuthenticator.java instead (but it is no longer available in 1.5). C# client works fine with NegotiateAuthenticator.java because sendError() is called, not setStatus():

            if (securityContext.getContinue() || ntlmPost) {
                response.setHeader("Connection", "keep-alive");
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED); //<------ C# client responds correctly to sendError() -------
                response.flushBuffer();
                return false;
            }

After I changed waffle/servlet/spi/NegotiateSecurityFilterProvider.java to call sendError(), the problem is gone. I think any C# client can reproduce the problem.

.NET implementation uses fixed buffer size

The .NET implementation uses a buffer size specified by Secur32.MAX_TOKEN_SIZE, which is currently set to 12KB. For tokens that exceed this size, an exception is raised:

System.ComponentModel.Win32Exception (0x80004005): The buffers supplied to a function was too small
   at Waffle.Windows.AuthProvider.WindowsSecurityContext..ctor(String username, WindowsCredentialsHandle credentials, String securityPackage, Int32 fContextReq, Int32 targetDataRep)
   at Waffle.Windows.AuthProvider.WindowsSecurityContext.GetCurrent(String package, String targetName, Int32 fContextReq, Int32 targetDataRep)

A similar issue in the Java implementation was fixed around a year ago (see ebedaf7). The .NET implementation should take the same approach.

Upgrade Guava to 17.0

Was: JEE7 server chokes when including waffle-jna 1.6 due to Guava issue 1433

I'm trying to use Waffle inside glassfish, but it chokes with :

[glassfish 4.0] [SEVERE] [] [javax.enterprise.system.core] [tid: _ThreadID=34 _ThreadName=admin-listener(2)] [timeMillis: 1369346915664] [levelValue: 1000] [[
Exception while loading the app : CDI deployment failure:WELD-001408 Unsatisfied dependencies for type [Set] with qualifiers [@default] at injection point [[BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] @Inject com.google.common.util.concurrent.ServiceManager(Set)]
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [Set] with qualifiers [@default] at injection point [[BackedAnnotatedParameter] Parameter 1 of [BackedAnnotatedConstructor] @Inject com.google.common.util.concurrent.ServiceManager(Set)]

The problem lies on google guava being discussed here:
https://code.google.com/p/guava-libraries/issues/detail?id=1433

My workaround was to revert back to guava 13.0.1

ie:

        <dependency>
            <groupId>com.github.dblock.waffle</groupId>
            <artifactId>waffle-jna</artifactId>
            <version>1.6</version>
            <exclusions>
                <exclusion>
                    <groupId>com.google.guava</groupId>
                    <artifactId>guava</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>13.0.1</version>
        </dependency>

Do you see any issue by downgrading the guava version?

Error parsing base64 (for non-WAFFLE authentication header)

I was trying out Milton which appears to have its own authentication enabled by default (something I will be desperately trying to rip out). So my browser was sending a header which looks like this:

Authorization:Digest username="admin", realm="milton", nonce="YjNjZDgxNDYtOGIwMS00NDk0LTlkMTItYzExMGJkNTcxZjli", uri="/case-user-data/431b971d9e1441d381adb277de4f39f8/test", response="ef5d94e786175aa9707d7b73e94298c1", qop=auth, nc=00000023, cnonce="cc84cadcfa74bf45"

On WAFFLE 1.5, this gives the error:

2014-11-05 16:52:06,606 [qtp987834065-67] 23773 WARN  org.eclipse.jetty.servlet.ServletHandler - /case-user-data/431b971d9e1441d381adb277de4f39f8/test
java.lang.StringIndexOutOfBoundsException: String index out of range: 246
    at java.lang.String.charAt(String.java:646)
    at waffle.util.Base64.decode(Unknown Source)
    at waffle.util.AuthorizationHeader.getTokenBytes(Unknown Source)
... omitting jetty stuff

On WAFFLE 1.7, you get a different error:

2014-11-05 17:03:42,177 [qtp1500151620-59] 11405 WARN  org.eclipse.jetty.servlet.ServletHandler - /case-user-data/431b971d9e1441d381adb277de4f39f8/test
java.lang.IllegalArgumentException: com.google.common.io.BaseEncoding$DecodingException: Expected padding character but found '"' at index 10
    at com.google.common.io.BaseEncoding.decode(BaseEncoding.java:228)
    at waffle.util.AuthorizationHeader.getTokenBytes(AuthorizationHeader.java:71)
    ... omitting jetty stuff
Caused by: com.google.common.io.BaseEncoding$DecodingException: Expected padding character but found '"' at index 10
    at com.google.common.io.BaseEncoding$StandardBaseEncoding$2.read(BaseEncoding.java:671)
    at com.google.common.io.BaseEncoding.decodeChecked(BaseEncoding.java:245)
    at com.google.common.io.BaseEncoding.decode(BaseEncoding.java:226)
    ... 35 more

I assume that WAFFLE is making some assumption that the string it receives will be in a particular format and then when it isn't, is just barfing on it when it should be ignoring it and letting a later filter or servlet handle the header.

Add support for SPNEGO OID for 0-length NTLM message POSTs

We have a system, where web browser sends post to tomcat servlet. Tomcat application is
protected by Waffle waffle.apache.NegotiateAuthenticator Valve. When using the system
with Internet Explorer, we are seeing post without content, ie. content-length is zero.
This upsets the server side application, of course.

Original discussion was here:
https://groups.google.com/forum/#!topic/waffle-users/fydgwCRkIqk

I compiled waffle 1.5 sources for my test environment and debugged what
happens inside waffle.util.AuthorizationHeader. Here are my notes about that:

Tomcat starting:

07:38:28.232 [localhost-startStop-1] DEBUG waffle.apache.NegotiateAuthenticator - [waffle.apache.NegotiateAuthenticator] loaded
07:38:28.237 [localhost-startStop-1] DEBUG waffle.apache.NegotiateAuthenticator - principal format: fqn
07:38:35.635 [localhost-startStop-1] INFO waffle.apache.NegotiateAuthenticator - [waffle.apache.NegotiateAuthenticator] started

marras 22, 2012 7:38:43 AP. org.apache.catalina.startup.Catalina start
INFO: Server startup in 15301 ms

Internet explorer started, typed http://localhost/koe.jsp into address:

07:38:45.746 [http-bio-80-exec-2] DEBUG waffle.apache.NegotiateAuthenticator - GET /koe.jsp, contentlength: -1
07:38:45.746 [http-bio-80-exec-2] DEBUG waffle.apache.NegotiateAuthenticator - authorization: Negotiate YHYGBisGAQUFAqBsMGqgMDAuBgorBgEEAYI3AgIKBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHqI2BDROVExNU1NQAAEAAACXsgjiAwADADEAAAAJAAkAKAAAAAYBsR0AAAAPR0xZQ0VSSU5FU0FE, ntlm post: false
07:38:45.748 [http-bio-80-exec-2] DEBUG waffle.apache.NegotiateAuthenticator - security package: Negotiate, connection id: 0:0:0:0:0:0:0:1:52722
07:38:45.749 [http-bio-80-exec-2] DEBUG waffle.apache.NegotiateAuthenticator - token buffer: 120 byte(s)
07:38:45.914 [http-bio-80-exec-2] DEBUG waffle.apache.NegotiateAuthenticator - continue required: true
07:38:45.915 [http-bio-80-exec-2] DEBUG waffle.apache.NegotiateAuthenticator - continue token: oYIBHzCCARugAwoBAaEMBgorBgEEAYI3AgIKooIBBASCAQBOVExNU1NQAAIAAAAGAAYAOAAAABXCieLB0LnMaI6u0sCqNwIAAAAAwgDCAD4AAAAGAbEdAAAAD1MAQQBEAAIABgBTAEEARAABABIARwBMAFkAQwBFAFIASQBOAEUABAAmAHMAYQBkAC4AcwB5AG4AYwByAG8AbgB0AGUAYwBoAC4AYwBvAG0AAwA6AGcAbAB5AGMAZQByAGkAbgBlAC4AcwBhAGQALgBzAHkAbgBjAHIAbwBuAHQAZQBjAGgALgBjAG8AbQAFACYAcwBhAGQALgBzAHkAbgBjAHIAbwBuAHQAZQBjAGgALgBjAG8AbQAHAAgAVydeZ4TIzQEAAAAA
07:38:45.942 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - GET /koe.jsp, contentlength: -1
07:38:45.942 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - authorization: Negotiate oXcwdaADCgEBoloEWE5UTE1TU1AAAwAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAABXCiOIGAbEdAAAAD1qJMaPqxOuvb9qtdigI0oSjEgQQAQAAAPUXp1AtIpqEAAAAAA==, ntlm post: false
07:38:45.942 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - security package: Negotiate, connection id: 0:0:0:0:0:0:0:1:52722
07:38:45.942 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - token buffer: 121 byte(s)
07:38:45.971 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - continue required: false
07:38:45.971 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - continue token: oRswGaADCgEAoxIEEAEAAABDh+CIwTbjqQAAAAA=
07:38:46.076 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - logged in user: SAD\asu (S-1-5-21-2089247947-1185871402-2587031589-1308)
07:38:46.213 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - roles: BUILTIN\Administrators, BUILTIN\Users, CONSOLE LOGON, Everyone, LOCAL, Mandatory Label\Medium Mandatory Level, NT AUTHORITY\Authenticated Users, NT AUTHORITY\INTERACTIVE, NT AUTHORITY\This Organization, NT AUTHORITY\This Organization Certificate, S-1-5-5-0-1678257, SAD\Domain Admins, SAD\Domain Users, SAD\ESX Admins, SAD\RTCUniversalGlobalReadOnlyGroup, SAD\RTCUniversalGlobalWriteGroup, SAD\ST, SAD\StoraEnso_EMS2011, SAD\asu, glycerine\HelpLibraryUpdaters, glycerine\Offer Remote Assistance Helpers
07:38:46.221 [http-bio-80-exec-3] DEBUG waffle.apache.NegotiateAuthenticator - session id:52E72A02CF44E9C7FFBD58DE84F92786
07:38:46.222 [http-bio-80-exec-3] INFO waffle.apache.NegotiateAuthenticator - successfully logged in user: SAD\asu

So, this worked ok, I guess.
Now I press submit:

07:38:52.994 [http-bio-80-exec-1] DEBUG waffle.apache.NegotiateAuthenticator - POST /koe.jsp, contentlength: 0
07:38:52.994 [http-bio-80-exec-1] DEBUG waffle.apache.NegotiateAuthenticator - authorization: Negotiate YHYGBisGAQUFAqBsMGqgMDAuBgorBgEEAYI3AgIKBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHqI2BDROVExNU1NQAAEAAACXsgjiAwADADEAAAAJAAkAKAAAAAYBsR0AAAAPR0xZQ0VSSU5FU0FE, ntlm post: false
07:38:52.994 [http-bio-80-exec-1] DEBUG waffle.apache.NegotiateAuthenticator - previously authenticated user: SAD\asu

This didn't work OK, it results as zero-length post to jsp page.
Next submit works ok:

07:38:58.435 [http-bio-80-exec-4] DEBUG waffle.apache.NegotiateAuthenticator - POST /koe.jsp, contentlength: 13
07:38:58.435 [http-bio-80-exec-4] DEBUG waffle.apache.NegotiateAuthenticator - authorization: , ntlm post: false
07:38:58.435 [http-bio-80-exec-4] DEBUG waffle.apache.NegotiateAuthenticator - previously authenticated user: SAD\asu

And next is ok:
07:39:11.148 [http-bio-80-exec-5] DEBUG waffle.apache.NegotiateAuthenticator - POST /koe.jsp, contentlength: 13
07:39:11.148 [http-bio-80-exec-5] DEBUG waffle.apache.NegotiateAuthenticator - authorization: , ntlm post: false
07:39:11.148 [http-bio-80-exec-5] DEBUG waffle.apache.NegotiateAuthenticator - previously authenticated user: SAD\asu

Now, wait until keepaliveTimeout passes and press submit again:

07:39:47.127 [http-bio-80-exec-8] DEBUG waffle.apache.NegotiateAuthenticator - POST /koe.jsp, contentlength: 0
07:39:47.127 [http-bio-80-exec-8] DEBUG waffle.apache.NegotiateAuthenticator - authorization: Negotiate YHYGBisGAQUFAqBsMGqgMDAuBgorBgEEAYI3AgIKBgkqhkiC9xIBAgIGCSqGSIb3EgECAgYKKwYBBAGCNwICHqI2BDROVExNU1NQAAEAAACXsgjiAwADADEAAAAJAAkAKAAAAAYBsR0AAAAPR0xZQ0VSSU5FU0FE, ntlm post: false
07:39:47.127 [http-bio-80-exec-8] DEBUG waffle.apache.NegotiateAuthenticator - previously authenticated user: SAD\asu

This results in jsp page seeing zero-length data and never the data sent by browser.

NtlmMessage.isNtlmMessage retuns false, because first byte of message signature is 0x60, not 0x4e as it expects.

Test web page is like this:
<%@ page import="javax.servlet.http._" %>

<title>test</title> <%=request.getParameter("testParm") == null && request.getMethod().equals("POST") ? "_**_ERROR**_\* POST DATA LOST!" : "OK!"%> parm:

Enhance Logging (stop the string concatenation madness)

Logging is still using string concatenation. Since this library is now fully using slf4j, it is time to remove string concatenation from logging.

Example

log.debug("some field is: " + field);

Can be

log.debug("some field is: {}");

This will result in some gain to speed of waffle as we will no longer instantiate strings to log when we may not be logging at that level.

At the same time, we should get rid of any other string concatenation. Use simple method that will append strings cleaner than using stringBuilders throughout possibly using Guava which is already part of the library.

IllegalStateException in Shiro when using waffle-shiro 1.7.0 for user not joined to a domain.

Shiro throws an IllegalStateException when waffle's NegotiateAuthenticationFilter.onAccessDenied() is called for users who are accessing the application from a PC that is not joined to any domain (User accessing application from Citrix server)

[java.lang.IllegalStateException: Principals returned from securityManager.login( token ) returned a null or empty value.  This value must be non null and populated with one or more elements.] with root cause
java.lang.IllegalStateException: Principals returned from securityManager.login( token ) returned a null or empty value.  This value must be non null and populated with one or more elements.
                at org.apache.shiro.subject.support.DelegatingSubject.login(DelegatingSubject.java:274)
                at org.apache.shiro.web.filter.authc.AuthenticatingFilter.executeLogin(AuthenticatingFilter.java:53)
                at waffle.shiro.negotiate.NegotiateAuthenticationFilter.onAccessDenied(NegotiateAuthenticationFilter.java:170)
                at org.apache.shiro.web.filter.AccessControlFilter.onAccessDenied(AccessControlFilter.java:133)
                at org.apache.shiro.web.filter.AccessControlFilter.onPreHandle(AccessControlFilter.java:162)
                at org.apache.shiro.web.filter.PathMatchingFilter.isFilterChainContinued(PathMatchingFilter.java:203)
                at org.apache.shiro.web.filter.PathMatchingFilter.preHandle(PathMatchingFilter.java:178)
                at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:131)
                at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
                at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
                at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449)
                at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365)
                at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
                at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
                at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383)
                at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362)
                at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:100)
                at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                at org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:90)
                at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
                at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
                at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
                at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
                at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
                at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
                at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:537)
                at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1085)
                at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:658)
                at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
                at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
                at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
                at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
                at java.lang.Thread.run(Thread.java:745)

Drop old branches

I've reviewed all the old branches on waffle currently. All could be deleted with exception of the one trying to solve issue #59. I realize most of these came originally from the old codeplex site but there really is no mirror over there any longer since this is only being worked on github. So I propose that we drop all those old branches that are no longer necessary. There is no code in those that isn't already on the current code base with exception of the #59 that may or may not still be needed depending on outcome of further investigation there. I can certainly remove the old branches provided the go-ahead is given.

Regex

Hello,

I have an issue for set up the range of the ip access rule on Waffle.

I have to enable waffle authentication for all IP adress, except one (192.168.10.9).

How can i do that with a regex ? What's the type of regex can I use (PCRE / Posix ?)

It's possible to set which IP adress who must access to Waffle authentication, but is they one way to set an IP adresse who must not authorized to use Waffle authentication ?

Excuse me for my English ...

Thanks :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.