├── .circleci └── config.yml ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── authn-servlet ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── okta │ │ └── servlet │ │ └── examples │ │ ├── Application.java │ │ ├── AuthenticationActions.java │ │ ├── AuthenticationLambdaServlet.java │ │ ├── AuthenticationServletContextListener.java │ │ ├── ExampleAuthenticationStateHandler.java │ │ ├── OktaFilter.java │ │ ├── OverlySimpleCsrfFilter.java │ │ ├── UserProfileServlet.java │ │ └── models │ │ └── Factor.java │ ├── resources │ └── logback.xml │ └── webapp │ ├── WEB-INF │ ├── authn │ │ ├── change-password.jsp │ │ ├── forgot-password.jsp │ │ ├── login.jsp │ │ ├── mfa-required.jsp │ │ ├── mfa-verify-sms.jsp │ │ ├── mfa-verify-totp.jsp │ │ ├── recovery.jsp │ │ ├── reset-password.jsp │ │ ├── unlock-account.jsp │ │ ├── unlock-recovery.jsp │ │ └── unsupported-state.jsp │ ├── home.jsp │ ├── includes │ │ ├── csrf.jsp │ │ ├── footer.jsp │ │ ├── form-errors.jsp │ │ ├── header.jsp │ │ └── menu.jsp │ └── user-profile.jsp │ ├── index.jsp │ └── static │ └── css │ └── style.css ├── mvnw ├── mvnw.cmd ├── pom.xml └── resource-server ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── okta │ │ └── servlet │ │ └── examples │ │ └── resourceserver │ │ ├── AccessUtil.java │ │ ├── MessagesServlet.java │ │ ├── OktaBearerFilter.java │ │ ├── ProfileServlet.java │ │ └── ResourceServerApplication.java └── resources │ └── logback.xml └── test └── resources └── testRunner.yml /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | general-platform-helpers: okta/general-platform-helpers@1.9 5 | python: circleci/python@2.1.1 6 | aws-cli: circleci/aws-cli@5.1 7 | 8 | aliases: 9 | 10 | - &build_steps 11 | - checkout 12 | - run: java -version 13 | - run: 14 | command: | 15 | sudo wget https://chromedriver.storage.googleapis.com/2.31/chromedriver_linux64.zip 16 | sudo unzip chromedriver_linux64.zip 17 | sudo rm chromedriver_linux64.zip 18 | sudo mv chromedriver /usr/bin/ 19 | sudo chmod 777 /usr/bin/chromedriver 20 | mvn -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -Pokta-tck dependency:resolve-plugins 21 | mvn -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -Pokta-tck install 22 | 23 | jobs: 24 | 25 | jdk17: 26 | docker: 27 | - image: cimg/openjdk:17.0.7 28 | environment: 29 | JVM_OPTS: -Xmx3200m 30 | steps: *build_steps 31 | 32 | reversing-labs: 33 | docker: 34 | - image: cimg/openjdk:17.0.7 35 | steps: 36 | - checkout 37 | 38 | - run: 39 | name: Install Python 40 | command: | 41 | sudo apt-get update 42 | sudo apt-get install -y python3 python3-pip 43 | sudo pip install --upgrade pip 44 | - run: 45 | name: Download Reverse Labs Scanner 46 | command: | 47 | curl https://dso-resources.oktasecurity.com/scanner \ 48 | -H "x-api-key: $DSO_RLSECURE_TOKEN" \ 49 | --output rl_wrapper-0.0.2+35ababa-py3-none-any.whl 50 | # Install the wrapper that was downloaded 51 | - run: 52 | name: Install RL Wrapper 53 | command: | 54 | pip install ./rl_wrapper-0.0.2+35ababa-py3-none-any.whl 55 | # Setup the AWS profile 56 | - aws-cli/setup: 57 | profile_name: default 58 | role_arn: $AWS_ARN 59 | region: us-east-1 60 | # Get the credentials and save to env 61 | - run: >- 62 | eval "$(aws configure export-credentials --profile default --format env)" 2> /dev/null 63 | # Run the wrapper, do not change anything here 64 | - run: 65 | name: Run Reversing Labs Wrapper Scanner 66 | command: | 67 | rl-wrapper \ 68 | --artifact ${CIRCLE_WORKING_DIRECTORY/#\~/$HOME} \ 69 | --name $CIRCLE_PROJECT_REPONAME\ 70 | --version $CIRCLE_SHA1\ 71 | --repository $CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME \ 72 | --commit $CIRCLE_SHA1 \ 73 | --build-env "circleci" \ 74 | --suppress_output 75 | workflows: 76 | "Circle CI Tests": 77 | jobs: 78 | - jdk17 79 | # See OKTA-624791 80 | semgrep: 81 | jobs: 82 | - general-platform-helpers/job-semgrep-scan: 83 | name: "Scan with Semgrep" 84 | context: 85 | - static-analysis 86 | "Malware Scanner": 87 | jobs: 88 | - reversing-labs: 89 | context: 90 | - static-analysis 91 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build2 2 | node_modules 3 | dist 4 | npm-debug.log 5 | travis_phantomjs 6 | .DS_Store 7 | .vscode 8 | 9 | public 10 | 11 | # Intellij 12 | .idea/ 13 | *.iml 14 | *.iws 15 | 16 | # Maven 17 | .classpath 18 | .project 19 | .settings 20 | target 21 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okta/samples-java-servlet/57c7d1f2f966520c8477233ff78e9dcf7484b677/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2018 Okta, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.0/apache-maven-3.6.0-bin.zip -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | 3 | jdk: 4 | - openjdk8 5 | - openjdk11 6 | 7 | install: 8 | - "true" 9 | - 10 | script: 11 | - "google-chrome --version" 12 | - "./mvnw -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -Pokta-tck dependency:resolve-plugins" 13 | - "./mvnw -B -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -Pokta-tck install" 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing to Okta Open Source Repos 2 | ====================================== 3 | 4 | Sign the CLA 5 | ------------ 6 | 7 | If you haven't already, [sign the CLA](https://developer.okta.com/cla/). Common questions/answers are also listed on the CLA page. 8 | 9 | Summary 10 | ------- 11 | This document covers how to contribute to an Okta Open Source project. These instructions assume you have a GitHub.com account, so if you don't have one you will have to create one. Your proposed code changes will be published to your own fork of the Okta Servlet Example project and you will submit a Pull Request for your changes to be added. 12 | 13 | _Lets get started!!!_ 14 | 15 | 16 | Fork the code 17 | ------------- 18 | 19 | In your browser, navigate to: [https://github.com/okta/samples-java-servlet](https://github.com/okta/samples-java-servlet) 20 | 21 | Fork the repository by clicking on the 'Fork' button on the top right hand side. The fork will happen and you will be taken to your own fork of the repository. Copy the Git repository URL by clicking on the clipboard next to the URL on the right hand side of the page under '**HTTPS** clone URL'. You will paste this URL when doing the following `git clone` command. 22 | 23 | On your computer, follow these steps to setup a local repository for working on the Okta Servlet Example: 24 | 25 | ``` bash 26 | $ git clone https://github.com/YOUR_ACCOUNT/samples-java-servlet.git 27 | $ cd samples-java-servlet 28 | $ git remote add upstream https://github.com/okta/samples-java-servlet.git 29 | $ git checkout master 30 | $ git fetch upstream 31 | $ git rebase upstream/master 32 | ``` 33 | 34 | 35 | Making changes 36 | -------------- 37 | 38 | It is important that you create a new branch to make changes on and that you do not change the `master` branch (other than to rebase in changes from `upstream/master`). In this example I will assume you will be making your changes to a branch called `feature_x`. This `feature_x` branch will be created on your local repository and will be pushed to your forked repository on GitHub. Once this branch is on your fork you will create a Pull Request for the changes to be added to the Okta Servlet Example project. 39 | 40 | It is best practice to create a new branch each time you want to contribute to the project and only track the changes for that pull request in this branch. 41 | 42 | ``` bash 43 | $ git checkout -b feature_x 44 | (make your changes) 45 | $ git status 46 | $ git add . 47 | $ git commit -a -m "descriptive commit message for your changes" 48 | ``` 49 | 50 | > The `-b` specifies that you want to create a new branch called `feature_x`. You only specify `-b` the first time you checkout because you are creating a new branch. Once the `feature_x` branch exists, you can later switch to it with only `git checkout feature_x`. 51 | 52 | 53 | Rebase `feature_x` to include updates from `upstream/master` 54 | ------------------------------------------------------------ 55 | 56 | It is important that you maintain an up-to-date `master` branch in your local repository. This is done by rebasing in the code changes from `upstream/master` (the official Okta Servlet Example project repository) into your local repository. You will want to do this before you start working on a feature as well as right before you submit your changes as a pull request. I recommend you do this process periodically while you work to make sure you are working off the most recent project code. 57 | 58 | This process will do the following: 59 | 60 | 1. Checkout your local `master` branch 61 | 2. Synchronize your local `master` branch with the `upstream/master` so you have all the latest changes from the project 62 | 3. Rebase the latest project code into your `feature_x` branch so it is up-to-date with the upstream code 63 | 64 | ``` bash 65 | $ git checkout master 66 | $ git fetch upstream 67 | $ git rebase upstream/master 68 | $ git checkout feature_x 69 | $ git rebase master 70 | ``` 71 | 72 | > Now your `feature_x` branch is up-to-date with all the code in `upstream/master`. 73 | 74 | 75 | Make a GitHub Pull Request to contribute your changes 76 | ----------------------------------------------------- 77 | 78 | When you are happy with your changes and you are ready to contribute them, you will create a Pull Request on GitHub to do so. This is done by pushing your local changes to your forked repository (default remote name is `origin`) and then initiating a pull request on GitHub. 79 | 80 | > **IMPORTANT:** Make sure you have rebased your `feature_x` branch to include the latest code from `upstream/master` _before_ you do this. 81 | 82 | ``` bash 83 | $ git push origin master 84 | $ git push origin feature_x 85 | ``` 86 | 87 | Now that the `feature_x` branch has been pushed to your GitHub repository, you can initiate the pull request. 88 | 89 | To initiate the pull request, do the following: 90 | 91 | 1. In your browser, navigate to your forked repository: [https://github.com/YOUR_ACCOUNT/samples-java-servlet](https://github.com/YOUR_ACCOUNT/samples-java-servlet) 92 | 2. Click the new button called '**Compare & pull request**' that showed up just above the main area in your forked repository 93 | 3. Validate the pull request will be into the upstream `master` and will be from your `feature_x` branch 94 | 4. Enter a detailed description of the work you have done and then click '**Send pull request**' 95 | 96 | If you are requested to make modifications to your proposed changes, make the changes locally on your `feature_x` branch, re-push the `feature_x` branch to your fork. The existing pull request should automatically pick up the change and update accordingly. 97 | 98 | 99 | Cleaning up after a successful pull request 100 | ------------------------------------------- 101 | 102 | Once the `feature_x` branch has been committed into the `upstream/master` branch, your local `feature_x` branch and the `origin/feature_x` branch are no longer needed. If you want to make additional changes, restart the process with a new branch. 103 | 104 | > **IMPORTANT:** Make sure that your changes are in `upstream/master` before you delete your `feature_x` and `origin/feature_x` branches! 105 | 106 | You can delete these deprecated branches with the following: 107 | 108 | ``` bash 109 | $ git checkout master 110 | $ git branch -D feature_x 111 | $ git push origin :feature_x 112 | ``` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and 27 | configuration files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object 31 | code, generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, 34 | made available under the License, as indicated by a copyright notice that is 35 | included in or attached to the work (an example is provided in the Appendix 36 | below). 37 | 38 | "Derivative Works" shall mean any work, whether in Source or Object form, that 39 | is based on (or derived from) the Work and for which the editorial revisions, 40 | annotations, elaborations, or other modifications represent, as a whole, an 41 | original work of authorship. For the purposes of this License, Derivative Works 42 | shall not include works that remain separable from, or merely link (or bind by 43 | name) to the interfaces of, the Work and Derivative Works thereof. 44 | 45 | "Contribution" shall mean any work of authorship, including the original 46 | version of the Work and any modifications or additions to that Work or 47 | Derivative Works thereof, that is intentionally submitted to Licensor for 48 | inclusion in the Work by the copyright owner or by an individual or Legal 49 | Entity authorized to submit on behalf of the copyright owner. For the purposes 50 | of this definition, "submitted" means any form of electronic, verbal, or 51 | written communication sent to the Licensor or its representatives, including 52 | but not limited to communication on electronic mailing lists, source code 53 | control systems, and issue tracking systems that are managed by, or on behalf 54 | of, the Licensor for the purpose of discussing and improving the Work, but 55 | excluding communication that is conspicuously marked or otherwise designated in 56 | writing by the copyright owner as "Not a Contribution." 57 | 58 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 59 | of whom a Contribution has been received by Licensor and subsequently 60 | incorporated within the Work. 61 | 2. Grant of Copyright License. Subject to the terms and conditions of this 62 | License, each Contributor hereby grants to You a perpetual, worldwide, 63 | non-exclusive, no-charge, royalty-free, irrevocable copyright license to 64 | reproduce, prepare Derivative Works of, publicly display, publicly perform, 65 | sublicense, and distribute the Work and such Derivative Works in Source or 66 | Object form. 67 | 68 | 3. Grant of Patent License. Subject to the terms and conditions of this 69 | License, each Contributor hereby grants to You a perpetual, worldwide, 70 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this 71 | section) patent license to make, have made, use, offer to sell, sell, import, 72 | and otherwise transfer the Work, where such license applies only to those 73 | patent claims licensable by such Contributor that are necessarily infringed by 74 | their Contribution(s) alone or by combination of their Contribution(s) with the 75 | Work to which such Contribution(s) was submitted. If You institute patent 76 | litigation against any entity (including a cross-claim or counterclaim in a 77 | lawsuit) alleging that the Work or a Contribution incorporated within the Work 78 | constitutes direct or contributory patent infringement, then any patent 79 | licenses granted to You under this License for that Work shall terminate as of 80 | the date such litigation is filed. 81 | 82 | 4. Redistribution. You may reproduce and distribute copies of the Work or 83 | Derivative Works thereof in any medium, with or without modifications, and in 84 | Source or Object form, provided that You meet the following conditions: 85 | 86 | (a) You must give any other recipients of the Work or Derivative Works a copy 87 | of this License; and 88 | 89 | (b) You must cause any modified files to carry prominent notices stating that 90 | You changed the files; and 91 | 92 | (c) You must retain, in the Source form of any Derivative Works that You 93 | distribute, all copyright, patent, trademark, and attribution notices from the 94 | Source form of the Work, excluding those notices that do not pertain to any 95 | part of the Derivative Works; and 96 | 97 | (d) If the Work includes a "NOTICE" text file as part of its distribution, then 98 | any Derivative Works that You distribute must include a readable copy of the 99 | attribution notices contained within such NOTICE file, excluding those notices 100 | that do not pertain to any part of the Derivative Works, in at least one of the 101 | following places: within a NOTICE text file distributed as part of the 102 | Derivative Works; within the Source form or documentation, if provided along 103 | with the Derivative Works; or, within a display generated by the Derivative 104 | Works, if and wherever such third-party notices normally appear. The contents 105 | of the NOTICE file are for informational purposes only and do not modify the 106 | License. You may add Your own attribution notices within Derivative Works that 107 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 108 | provided that such additional attribution notices cannot be construed as 109 | modifying the License. 110 | 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a 114 | whole, provided Your use, reproduction, and distribution of the Work otherwise 115 | complies with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 118 | Contribution intentionally submitted for inclusion in the Work by You to the 119 | Licensor shall be under the terms and conditions of this License, without any 120 | additional terms or conditions. Notwithstanding the above, nothing herein shall 121 | supersede or modify the terms of any separate license agreement you may have 122 | executed with Licensor regarding such Contributions. 123 | 124 | 6. Trademarks. This License does not grant permission to use the trade names, 125 | trademarks, service marks, or product names of the Licensor, except as required 126 | for reasonable and customary use in describing the origin of the Work and 127 | reproducing the content of the NOTICE file. 128 | 129 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 130 | writing, Licensor provides the Work (and each Contributor provides its 131 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 132 | KIND, either express or implied, including, without limitation, any warranties 133 | or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 134 | PARTICULAR PURPOSE. You are solely responsible for determining the 135 | appropriateness of using or redistributing the Work and assume any risks 136 | associated with Your exercise of permissions under this License. 137 | 138 | 8. Limitation of Liability. In no event and under no legal theory, whether in 139 | tort (including negligence), contract, or otherwise, unless required by 140 | applicable law (such as deliberate and grossly negligent acts) or agreed to in 141 | writing, shall any Contributor be liable to You for damages, including any 142 | direct, indirect, special, incidental, or consequential damages of any 143 | character arising as a result of this License or out of the use or inability to 144 | use the Work (including but not limited to damages for loss of goodwill, work 145 | stoppage, computer failure or malfunction, or any and all other commercial 146 | damages or losses), even if such Contributor has been advised of the 147 | possibility of such damages. 148 | 149 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or 150 | Derivative Works thereof, You may choose to offer, and charge a fee for, 151 | acceptance of support, warranty, indemnity, or other liability obligations 152 | and/or rights consistent with this License. However, in accepting such 153 | obligations, You may act only on Your own behalf and on Your sole 154 | responsibility, not on behalf of any other Contributor, and only if You agree 155 | to indemnify, defend, and hold each Contributor harmless for any liability 156 | incurred by, or claims asserted against, such Contributor by reason of your 157 | accepting any such warranty or additional liability. 158 | 159 | END OF TERMS AND CONDITIONS 160 | 161 | APPENDIX: How to apply the Apache License to your work. 162 | 163 | To apply the Apache License to your work, attach the following boilerplate 164 | notice, with the fields enclosed by brackets "[]" replaced with your own 165 | identifying information. (Don't include the brackets!) The text should be 166 | enclosed in the appropriate comment syntax for the file format. We also 167 | recommend that a file or class name and description of purpose be included on 168 | the same "printed page" as the copyright notice for easier identification 169 | within third-party archives. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java Servlet Sample Applications for Okta 2 | 3 | This repository contains sample applications that show you how to integrate various Okta use-cases into an existing Java Servlet based application 4 | 5 | Please find the sample that fits your use-case from the table below. 6 | 7 | | Sample | Description | Use-Case | 8 | |--------|-------------|----------| 9 | | [Okta Authentication SDK](/authn-servlet) | A simple Servlet application that uses Okta's Authentication SDK for user authentication. | For existing Servlet web applications with server-side rendered pages. | 10 | | [Resource Server](/resource-server) | This is a sample API resource server that shows you how to authenticate requests with access tokens that have been issued by Okta. | API or Single-Page applications. | 11 | -------------------------------------------------------------------------------- /authn-servlet/README.md: -------------------------------------------------------------------------------- 1 | # Okta Authentication SDK & Java Servlets 2 | 3 | This example shows you how to use the [Okta Java Authentication SDK][] to login a user to a Servlet based application. This is a sample application meant to show how to integrate [Okta Java Authentication SDK][] into existing frameworks or applications and is NOT a production ready application (See [OWASP Top Ten Cheat Sheet](https://www.owasp.org/index.php/OWASP_Top_Ten_Cheat_Sheet) for more tips). 4 | 5 | ## Is This Library Right for Me? 6 | 7 | This SDK is a convenient HTTP client wrapper for [Okta's Authentication API](https://developer.okta.com/docs/api/resources/authn/). These APIs are powerful and useful if you need to achieve one of these cases: 8 | 9 | - You have an existing application that needs to accept primary credentials (username and password) and do custom logic before communicating with Okta. 10 | - You have significantly custom authentication workflow or UI needs, such that Okta’s hosted sign-in page or [Sign-In Widget](https://github.com/okta/okta-signin-widget) do not give you enough flexibility. 11 | 12 | The power of this SDK comes with more responsibility and maintenance: you will have to design your authentication workflow and UIs by hand, respond to all relevant states in Okta’s authentication state machine, and keep up to date with new features and states in Okta. 13 | 14 | Otherwise, most applications can use the Okta hosted sign-in page or the Sign-in Widget. For these cases, you should use [Okta's Spring Boot Starter](https://github.com/okta/okta-spring-boot), [Spring Security](https://developer.okta.com/blog/2017/12/18/spring-security-5-oidc) or other OIDC/OAuth 2.0 library. 15 | 16 | ## Authentication State Machine 17 | 18 | ![State Model Diagram](https://raw.githubusercontent.com/okta/okta.github.io/source/_source/_assets/img/auth-state-model.png "State Model Diagram") 19 | 20 | # Supported Use Cases: 21 | 22 | All pages are server side rendered with JSPs. 23 | 24 | - Basic username & password login 25 | - Display current user details 26 | - Logout (`session.invalidate()`) 27 | - Forgot Password 28 | - User Lockout notification 29 | - Self service password reset via `SMS` or `CALL` 30 | - MFA support for `TOTP` and `SMS` 31 | 32 | ## Prerequisites 33 | 34 | Before running this sample, you will need the following: 35 | 36 | * An Okta Developer Account, you can sign up for one at https://developer.okta.com/signup/. 37 | * The source code from this repository: 38 | 39 | ``` 40 | git clone https://github.com/okta/samples-java-servlet.git 41 | cd samples-java-servlet 42 | ``` 43 | 44 | ## Running This Example 45 | 46 | There is a `pom.xml` at the root of this project, that exists to build all of the projects. Each project is independent and could be copied out of this repo as a primer for your own application. 47 | 48 | You also need to grab the your Okta Domain, for example, `https://dev-123456.okta.com`. 49 | 50 | Plug these values into the `mvn` commands used to start the application. 51 | 52 | ```bash 53 | cd authn-servlet 54 | mvn -Dokta.client.orgUrl=https://{yourOktaDomain} 55 | ``` 56 | 57 | Now navigate to http://localhost:8080 in your browser. 58 | 59 | If you see a home page that prompts you to login, then things are working! 60 | 61 | You can login with the same account that you created when signing up for your Developer Org, or you can use a known username and password from your Okta Directory. 62 | 63 | [Okta Java Authentication SDK]: https://github.com/okta/okta-auth-java 64 | -------------------------------------------------------------------------------- /authn-servlet/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 4.0.0 20 | 21 | com.okta.servlet.examples 22 | authn-servlet 23 | 1-SNAPSHOT 24 | Okta Servlet Samples :: Basic Authn API Usage 25 | See README for details. 26 | 27 | 28 | UTF-8 29 | 12.0.12 30 | 31 | 32 | 33 | 34 | com.okta.authn.sdk 35 | okta-authn-sdk-api 36 | 0.3.0 37 | 38 | 39 | com.okta.authn.sdk 40 | okta-authn-sdk-impl 41 | 0.3.0 42 | runtime 43 | 44 | 45 | com.okta.sdk 46 | okta-sdk-okhttp 47 | 8.2.5 48 | runtime 49 | 50 | 51 | 52 | org.eclipse.jetty 53 | jetty-annotations 54 | ${jetty.version} 55 | 56 | 57 | org.eclipse.jetty 58 | jetty-server 59 | ${jetty.version} 60 | 61 | 62 | org.eclipse.jetty 63 | jetty-webapp 64 | ${jetty.version} 65 | 66 | 67 | org.eclipse.jetty 68 | jetty-xml 69 | 10.0.16 70 | 71 | 72 | org.eclipse.jetty 73 | apache-jsp 74 | ${jetty.version} 75 | 76 | 77 | org.apache.httpcomponents 78 | httpclient 79 | 4.5.14 80 | 81 | 82 | com.fasterxml.jackson.core 83 | jackson-databind 84 | 2.15.1 85 | 86 | 87 | com.squareup.okio 88 | okio-jvm 89 | 3.6.0 90 | runtime 91 | 92 | 93 | org.eclipse.jetty 94 | apache-jstl 95 | 10.0.15 96 | pom 97 | 98 | 99 | javax.servlet 100 | javax.servlet-api 101 | 3.1.0 102 | 103 | 104 | 105 | ch.qos.logback 106 | logback-classic 107 | 1.4.14 108 | runtime 109 | 110 | 111 | ch.qos.logback 112 | logback-core 113 | 1.4.14 114 | 115 | 116 | 117 | org.yaml 118 | snakeyaml 119 | 2.0 120 | 121 | 122 | org.jetbrains.kotlin 123 | kotlin-stdlib 124 | 1.8.22 125 | 126 | 127 | 128 | commons-codec 129 | commons-codec 130 | 1.16.0 131 | 132 | 133 | 134 | 135 | 136 | compile exec:java 137 | 138 | 139 | maven-compiler-plugin 140 | 3.11.0 141 | 142 | 17 143 | 17 144 | 145 | 146 | 147 | org.codehaus.mojo 148 | exec-maven-plugin 149 | 3.1.0 150 | 151 | 152 | 153 | java 154 | 155 | 156 | 157 | 158 | com.okta.servlet.examples.Application 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples; 17 | 18 | import org.eclipse.jetty.annotations.AnnotationConfiguration; 19 | import org.eclipse.jetty.server.Server; 20 | import org.eclipse.jetty.util.resource.Resource; 21 | import org.eclipse.jetty.webapp.Configuration; 22 | import org.eclipse.jetty.webapp.WebAppContext; 23 | import org.eclipse.jetty.webapp.WebInfConfiguration; 24 | import org.eclipse.jetty.webapp.WebXmlConfiguration; 25 | 26 | import java.io.File; 27 | 28 | /** 29 | * Simple embedded web application to make running this sample easier. Servlet and Context Listener are registered 30 | * via annotations and should work in a traditional WAR file app the same way. 31 | */ 32 | public class Application { 33 | 34 | public static void main(String[] args) throws Exception { 35 | 36 | WebAppContext webapp = new WebAppContext(); 37 | webapp.setBaseResource(Resource.newResource(new File( "src/main/webapp"))); 38 | webapp.setContextPath("/"); 39 | webapp.setWelcomeFiles(new String[]{"index.jsp"}); 40 | webapp.setParentLoaderPriority(true); 41 | webapp.setConfigurations(new Configuration[] { 42 | new AnnotationConfiguration(), 43 | new WebInfConfiguration(), 44 | new WebXmlConfiguration() 45 | }); 46 | 47 | // scan everything for annotations, jstl, web fragments, etc 48 | webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*"); 49 | 50 | Server server = new Server(8080); 51 | server.setHandler(webapp); 52 | server.start(); 53 | server.join(); 54 | } 55 | } -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/AuthenticationActions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples; 17 | 18 | import com.okta.authn.sdk.AuthenticationException; 19 | import com.okta.authn.sdk.client.AuthenticationClient; 20 | import com.okta.authn.sdk.resource.AuthenticationResponse; 21 | import com.okta.authn.sdk.resource.VerifyFactorRequest; 22 | import com.okta.authn.sdk.resource.VerifyPassCodeFactorRequest; 23 | import com.okta.authn.sdk.resource.VerifyRecoveryRequest; 24 | import com.okta.sdk.resource.user.factor.FactorType; 25 | import com.okta.servlet.examples.models.Factor; 26 | 27 | import javax.servlet.ServletException; 28 | import javax.servlet.http.HttpServletRequest; 29 | import javax.servlet.http.HttpServletResponse; 30 | import java.io.IOException; 31 | import java.util.Arrays; 32 | import java.util.List; 33 | import java.util.stream.Collectors; 34 | 35 | /** 36 | * This class contains logic needed to collect and display JSPs in order to advance a user through Okta's Authentication State Machine. 37 | */ 38 | class AuthenticationActions { 39 | 40 | static final String PREVIOUS_AUTHN_RESULT = AuthenticationResponse.class.getName(); 41 | 42 | private final AuthenticationClient authenticationClient; 43 | 44 | AuthenticationActions(AuthenticationClient authenticationClient) { 45 | this.authenticationClient = authenticationClient; 46 | } 47 | 48 | /** 49 | * /authn/login 50 | */ 51 | void login(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 52 | 53 | String username = request.getParameter("username"); 54 | String password = request.getParameter("password"); 55 | 56 | authenticationClient.authenticate(username, password.toCharArray(), "/", new ExampleAuthenticationStateHandler(request, response)); 57 | } 58 | 59 | /** 60 | * /authn/logout 61 | */ 62 | void logout(HttpServletRequest request, HttpServletResponse response) throws IOException { 63 | 64 | if (request.getSession(false) != null) { 65 | request.getSession().invalidate(); 66 | } 67 | response.sendRedirect("/"); 68 | } 69 | 70 | /** 71 | * /authn/change-password 72 | */ 73 | void changePassword(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 74 | 75 | String oldPassword = request.getParameter("oldPassword"); 76 | String newPassword = request.getParameter("newPassword"); 77 | 78 | authenticationClient.changePassword(oldPassword.toCharArray(), 79 | newPassword.toCharArray(), 80 | getPreviousAuthResult(request).getStateToken(), 81 | new ExampleAuthenticationStateHandler(request, response)); 82 | } 83 | 84 | /** 85 | * /authn/mfa/verify/totp 86 | */ 87 | void mfaVerifyTotp(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 88 | 89 | String passCode = request.getParameter("passCode"); 90 | 91 | AuthenticationResponse previousAuthResult = getPreviousAuthResult(request); 92 | com.okta.authn.sdk.resource.Factor factor = getFactor("totp", previousAuthResult); 93 | 94 | VerifyFactorRequest verifyFactorRequest = authenticationClient.instantiate(VerifyPassCodeFactorRequest.class) 95 | .setPassCode(passCode) 96 | .setStateToken(previousAuthResult.getStateToken()); 97 | 98 | authenticationClient.verifyFactor(factor.getId(), verifyFactorRequest, new ExampleAuthenticationStateHandler(request, response)); 99 | } 100 | 101 | /** 102 | * /authn/mfa/verify/sms 103 | */ 104 | void mfaVerifySms(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 105 | 106 | String passCode = request.getParameter("passCode"); 107 | 108 | AuthenticationResponse previousAuthResult = getPreviousAuthResult(request); 109 | com.okta.authn.sdk.resource.Factor factor = getFactor("sms", previousAuthResult); 110 | 111 | VerifyFactorRequest verifyFactorRequest = authenticationClient.instantiate(VerifyPassCodeFactorRequest.class) 112 | .setPassCode(passCode) 113 | .setStateToken(previousAuthResult.getStateToken()); 114 | 115 | authenticationClient.verifyFactor(factor.getId(), verifyFactorRequest, new ExampleAuthenticationStateHandler(request, response)); 116 | } 117 | 118 | /** 119 | * /authn/mfa/resend/sms 120 | */ 121 | void mfaResendSms(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 122 | 123 | AuthenticationResponse previousAuthResult = getPreviousAuthResult(request); 124 | com.okta.authn.sdk.resource.Factor factor = getFactor("sms", previousAuthResult); 125 | authenticationClient.resendVerifyFactor(factor.getId(), previousAuthResult.getStateToken(), new ExampleAuthenticationStateHandler(request, response)); 126 | } 127 | 128 | /** 129 | * /authn/mfa/verify/totp 130 | */ 131 | void renderMfaVerifyTotp(HttpServletRequest request, HttpServletResponse response) { 132 | 133 | AuthenticationResponse authenticationResponse = getPreviousAuthResult(request); 134 | com.okta.authn.sdk.resource.Factor factor = getFactor("totp", authenticationResponse); 135 | request.setAttribute("factor", factor); 136 | forward("/WEB-INF/authn/mfa-verify-totp.jsp", request, response); 137 | } 138 | 139 | /** 140 | * /authn/mfa/verify/sms 141 | */ 142 | void renderMfaVerifySms(HttpServletRequest request, HttpServletResponse response) { 143 | 144 | AuthenticationResponse authenticationResponse = getPreviousAuthResult(request); 145 | com.okta.authn.sdk.resource.Factor factor = getFactor("sms", authenticationResponse); 146 | request.setAttribute("factor", factor); 147 | forward("/WEB-INF/authn/mfa-verify-sms.jsp", request, response); 148 | } 149 | 150 | /** 151 | * /authn/unlock 152 | */ 153 | void unlockAccount(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 154 | 155 | String username = request.getParameter("username"); 156 | String factorType = request.getParameter("factor"); 157 | authenticationClient.unlockAccount(username, FactorType.valueOf(factorType), "/", new ExampleAuthenticationStateHandler(request, response)); 158 | } 159 | 160 | /** 161 | * /authn/unlock/recovery 162 | */ 163 | void unlockRecovery(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 164 | 165 | String passCode = request.getParameter("passCode"); 166 | 167 | AuthenticationResponse previousAuthResult = getPreviousAuthResult(request); 168 | VerifyRecoveryRequest recoveryRequest = authenticationClient.instantiate(VerifyRecoveryRequest.class) 169 | .setStateToken(previousAuthResult.getStateToken()) 170 | .setPassCode(passCode); 171 | authenticationClient.verifyUnlockAccount(FactorType.valueOf(previousAuthResult.getFactorType()), recoveryRequest, new ExampleAuthenticationStateHandler(request, response)); 172 | } 173 | 174 | /** 175 | * /authn/recovery 176 | */ 177 | void renderRecovery(HttpServletRequest request, HttpServletResponse response) { 178 | 179 | AuthenticationResponse previousAuthResult = getPreviousAuthResult(request); 180 | String question = previousAuthResult.getUser().getRecoveryQuestion().get("question"); 181 | request.setAttribute("question", question); 182 | forward("/WEB-INF/authn/recovery.jsp", request, response); 183 | } 184 | 185 | /** 186 | * /authn/recovery 187 | */ 188 | void recovery(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 189 | 190 | String answer = request.getParameter("answer"); 191 | AuthenticationResponse previousAuthResult = getPreviousAuthResult(request); 192 | authenticationClient.answerRecoveryQuestion(answer, 193 | previousAuthResult.getStateToken(), 194 | new ExampleAuthenticationStateHandler(request, response)); 195 | } 196 | 197 | /** 198 | * /authn/mfa-required 199 | */ 200 | void listMfaVerifyTypes(HttpServletRequest request, HttpServletResponse response) { 201 | 202 | AuthenticationResponse authResponse = getPreviousAuthResult(request); 203 | 204 | List supportedFactors = Arrays.asList(FactorType.CALL, FactorType.EMAIL, FactorType.SMS); 205 | 206 | List factors = authResponse.getFactors().stream() 207 | .map(authFactor -> { 208 | String shortType = Factor.relativeLink(authFactor); 209 | 210 | String extraInfo = ""; 211 | if (!supportedFactors.contains(authFactor.getType())) { 212 | extraInfo = "Factor type '" + authFactor.getType() + "' is not supported by this sample application"; 213 | } 214 | 215 | return new Factor(authFactor.getId(), 216 | shortType, 217 | authFactor.getProvider().name(), 218 | authFactor.getVendorName(), 219 | extraInfo, 220 | authFactor.getProfile(), 221 | "/authn/mfa/verify/" + shortType); 222 | }) 223 | .collect(Collectors.toList()); 224 | request.setAttribute("factors", factors); 225 | 226 | forward("/WEB-INF/authn/mfa-required.jsp", request, response); 227 | } 228 | 229 | /** 230 | * /authn/forgot-password 231 | */ 232 | void forgotPassword(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 233 | 234 | String username = request.getParameter("username"); 235 | String factorType = request.getParameter("factor"); 236 | authenticationClient.recoverPassword(username, FactorType.valueOf(factorType), "/?breaking-the-law", new ExampleAuthenticationStateHandler(request, response)); 237 | } 238 | 239 | /** 240 | * /authn/reset-password 241 | */ 242 | void resetPassword(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { 243 | 244 | String newPassword = request.getParameter("newPassword"); 245 | authenticationClient.resetPassword(newPassword.toCharArray(), 246 | getPreviousAuthResult(request).getStateToken(), 247 | new ExampleAuthenticationStateHandler(request, response)); 248 | } 249 | 250 | private com.okta.authn.sdk.resource.Factor getFactor(String type, AuthenticationResponse authenticationResponse) { 251 | 252 | FactorType oktaType = Factor.fromRelativeLink(type); 253 | return authenticationResponse.getFactors().stream() 254 | .filter(it -> it.getType().equals(oktaType)) 255 | .findFirst().get(); 256 | } 257 | 258 | private AuthenticationResponse getPreviousAuthResult(HttpServletRequest request) { 259 | return (AuthenticationResponse) request.getSession(true).getAttribute(PREVIOUS_AUTHN_RESULT); 260 | } 261 | 262 | static void forward(String path, HttpServletRequest request, HttpServletResponse response) { 263 | try { 264 | request.getRequestDispatcher(path).forward(request, response); 265 | } catch (ServletException | IOException e) { 266 | throw new IllegalStateException("Unable to forward to path: "+ path, e); 267 | } 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/AuthenticationLambdaServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples; 17 | 18 | import com.okta.authn.sdk.AuthenticationException; 19 | import com.okta.sdk.resource.ResourceException; 20 | 21 | import javax.servlet.ServletException; 22 | import javax.servlet.http.HttpServlet; 23 | import javax.servlet.http.HttpServletRequest; 24 | import javax.servlet.http.HttpServletResponse; 25 | import java.io.IOException; 26 | 27 | import static com.okta.servlet.examples.AuthenticationActions.forward; 28 | 29 | /** 30 | * Boiler plate code reduction to help make this sample project easier to follow. Authentication related servlets are configured in 31 | * {@code OktaFilter.init} by calling: 32 | *
33 |  *     registerAction(filterConfig, "/authn/login","/WEB-INF/authn/login.jsp", actions::login);
34 |  * 
35 | */ 36 | class AuthenticationLambdaServlet extends HttpServlet { 37 | private final AuthenticationServletHandler renderConsumer; 38 | private final AuthenticationServletHandler postConsumer; 39 | 40 | AuthenticationLambdaServlet(String path, 41 | AuthenticationServletHandler postConsumer) { 42 | this((request, response) -> forward(path, request, response), postConsumer); 43 | } 44 | 45 | AuthenticationLambdaServlet(AuthenticationServletHandler renderConsumer, 46 | AuthenticationServletHandler postConsumer) { 47 | this.renderConsumer = renderConsumer; 48 | this.postConsumer = postConsumer; 49 | } 50 | 51 | @Override 52 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 53 | 54 | if (renderConsumer == null) { 55 | super.doGet(req, resp); 56 | return; 57 | } 58 | 59 | try { 60 | renderConsumer.service(req, resp); 61 | } catch (AuthenticationException | ResourceException e) { 62 | req.setAttribute("error", e); 63 | forward("/WEB-INF/authn/login.jsp", req, resp); 64 | } 65 | } 66 | 67 | @Override 68 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 69 | 70 | if (postConsumer == null) { 71 | super.doGet(req, resp); 72 | return; 73 | } 74 | 75 | try { 76 | postConsumer.service(req, resp); 77 | } catch (AuthenticationException | ResourceException e) { 78 | 79 | // on error, set the error attribute then render the page again 80 | req.setAttribute("error", e); 81 | doGet(req, resp); 82 | } 83 | } 84 | 85 | @FunctionalInterface 86 | interface AuthenticationServletHandler { 87 | void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, AuthenticationException; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/AuthenticationServletContextListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples; 17 | 18 | import javax.servlet.DispatcherType; 19 | import javax.servlet.Filter; 20 | import javax.servlet.ServletContext; 21 | import javax.servlet.ServletContextEvent; 22 | import javax.servlet.ServletContextListener; 23 | import javax.servlet.annotation.WebListener; 24 | 25 | import com.okta.authn.sdk.client.AuthenticationClient; 26 | import com.okta.authn.sdk.client.AuthenticationClients; 27 | import com.okta.servlet.examples.AuthenticationLambdaServlet.AuthenticationServletHandler; 28 | 29 | import java.util.EnumSet; 30 | 31 | @WebListener 32 | public class AuthenticationServletContextListener implements ServletContextListener { 33 | 34 | private AuthenticationActions actions; 35 | 36 | @Override 37 | public void contextInitialized(ServletContextEvent sce) { 38 | 39 | // configuration can be pulled from various sources, see https://github.com/okta/okta-auth-java#configuration-reference 40 | AuthenticationClient authenticationClient = AuthenticationClients.builder().build(); 41 | 42 | actions = new AuthenticationActions(authenticationClient); 43 | 44 | ServletContext servletContext = sce.getServletContext(); 45 | registerFilter(servletContext, "/*", new OverlySimpleCsrfFilter()); 46 | registerFilter(servletContext, "/*", new OktaFilter()); 47 | 48 | registerAction(servletContext, "/authn/login","/WEB-INF/authn/login.jsp", actions::login); 49 | registerAction(servletContext, "/authn/logout", (String) null, actions::logout); 50 | registerAction(servletContext, "/authn/change-password","/WEB-INF/authn/change-password.jsp", actions::changePassword); 51 | registerAction(servletContext, "/authn/mfa-required", actions::listMfaVerifyTypes, null); 52 | registerAction(servletContext, "/authn/mfa/verify/totp", actions::renderMfaVerifyTotp, actions::mfaVerifyTotp); 53 | registerAction(servletContext, "/authn/mfa/verify/sms", actions::renderMfaVerifySms, actions::mfaVerifySms); 54 | registerAction(servletContext, "/authn/mfa/resend/sms", actions::renderMfaVerifySms, actions::mfaResendSms); 55 | registerAction(servletContext, "/authn/unlock", "/WEB-INF/authn/unlock-account.jsp", actions::unlockAccount); 56 | registerAction(servletContext, "/authn/unlock/recovery", "/WEB-INF/authn/unlock-recovery.jsp", actions::unlockRecovery); 57 | registerAction(servletContext, "/authn/recovery", actions::renderRecovery, actions::recovery); 58 | registerAction(servletContext, "/authn/forgot-password", "/WEB-INF/authn/forgot-password.jsp", actions::forgotPassword); 59 | registerAction(servletContext, "/authn/reset-password", "/WEB-INF/authn/reset-password.jsp", actions::resetPassword); 60 | } 61 | 62 | @Override 63 | public void contextDestroyed(ServletContextEvent sce) { 64 | actions = null; 65 | } 66 | 67 | private void registerAction(ServletContext servletContext, String path, String view, AuthenticationServletHandler postHandler) { 68 | servletContext.addServlet(path, new AuthenticationLambdaServlet(view, postHandler)) 69 | .addMapping(path); 70 | } 71 | 72 | private void registerAction(ServletContext servletContext, String path, AuthenticationServletHandler renderHandler, AuthenticationServletHandler postHandler) { 73 | servletContext.addServlet(path, new AuthenticationLambdaServlet(renderHandler, postHandler)) 74 | .addMapping(path); 75 | } 76 | 77 | private void registerFilter(ServletContext servletContext, String path, Filter filter) { 78 | servletContext.addFilter(filter.getClass().getName(), filter) 79 | .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, path); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/ExampleAuthenticationStateHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples; 17 | 18 | import com.okta.authn.sdk.AuthenticationStateHandlerAdapter; 19 | import com.okta.authn.sdk.resource.AuthenticationResponse; 20 | 21 | import javax.servlet.http.HttpServletRequest; 22 | import javax.servlet.http.HttpServletResponse; 23 | import java.io.IOException; 24 | import java.util.Locale; 25 | 26 | /** 27 | * An {@link com.okta.authn.sdk.AuthenticationStateHandler AuthenticationStateHandler} that redirects to a JSP corresponding a given state. 28 | * The {@link #handleSuccess} is a special case, on "success" when there is a {@code sessionToken} the user is considered authenticated. 29 | *

30 | * NOTE: the "success" state is also used in other flows, you MUST check for the presents of a {@code sessionToken}. 31 | */ 32 | class ExampleAuthenticationStateHandler extends AuthenticationStateHandlerAdapter { 33 | 34 | private final HttpServletRequest request; 35 | private final HttpServletResponse response; 36 | 37 | ExampleAuthenticationStateHandler(HttpServletRequest request, HttpServletResponse response) { 38 | this.request = request; 39 | this.response = response; 40 | } 41 | 42 | @Override 43 | public void handleSuccess(AuthenticationResponse successResponse) { 44 | // the last request was a success, but if we do not have a session token 45 | // we need to force the flow to start over 46 | if (successResponse.getSessionToken() != null) { 47 | // if we have a Session Token add the corresponding user to the Session 48 | request.getSession(true).setAttribute(OktaFilter.USER_SESSION_KEY, successResponse.getUser()); 49 | } 50 | 51 | String relayState = successResponse.getRelayState(); 52 | String dest = relayState != null ? relayState : "/"; 53 | redirect(dest, successResponse); 54 | } 55 | 56 | @Override 57 | public void handlePasswordExpired(AuthenticationResponse passwordExpired) { 58 | redirect("/authn/change-password", passwordExpired); 59 | } 60 | 61 | @Override 62 | public void handleMfaRequired(AuthenticationResponse mfaRequiredResponse) { 63 | redirect("/authn/mfa-required", mfaRequiredResponse); 64 | } 65 | 66 | @Override 67 | public void handleMfaChallenge(AuthenticationResponse mfaChallengeResponse) { 68 | String factorType = mfaChallengeResponse.getFactors().get(0).getType().name().toLowerCase(Locale.ENGLISH); 69 | redirect("/authn/mfa/verify/"+ factorType, mfaChallengeResponse); 70 | } 71 | 72 | @Override 73 | public void handleLockedOut(AuthenticationResponse lockedOutResponse) { 74 | redirect("/authn/unlock", lockedOutResponse); 75 | } 76 | 77 | @Override 78 | public void handleRecoveryChallenge(AuthenticationResponse recoveryChallenge) { 79 | redirect("/authn/unlock/recovery", recoveryChallenge); 80 | } 81 | 82 | @Override 83 | public void handleRecovery(AuthenticationResponse recoveryResponse) { 84 | redirect("/authn/recovery", recoveryResponse); 85 | } 86 | 87 | @Override 88 | public void handlePasswordReset(AuthenticationResponse passwordReset) { 89 | redirect("/authn/reset-password", passwordReset); 90 | } 91 | 92 | @Override 93 | public void handleUnknown(AuthenticationResponse unknownResponse) { 94 | redirect("/authn/login?error=Unsupported State: "+ unknownResponse.getStatus().name(), unknownResponse); 95 | } 96 | 97 | private void redirect(String location, AuthenticationResponse authenticationResponse) { 98 | try { 99 | setAuthNResult(authenticationResponse); 100 | response.sendRedirect(location); 101 | } catch (IOException e) { 102 | throw new IllegalStateException("failed to redirect.", e); 103 | } 104 | } 105 | 106 | private void setAuthNResult(AuthenticationResponse authenticationResponse) { 107 | request.getSession(true).setAttribute(AuthenticationActions.PREVIOUS_AUTHN_RESULT, authenticationResponse); 108 | } 109 | } -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/OktaFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples; 17 | 18 | import com.okta.authn.sdk.resource.User; 19 | 20 | import javax.servlet.Filter; 21 | import javax.servlet.FilterChain; 22 | import javax.servlet.FilterConfig; 23 | import javax.servlet.ServletException; 24 | import javax.servlet.ServletRequest; 25 | import javax.servlet.ServletResponse; 26 | import javax.servlet.http.HttpServletRequest; 27 | import javax.servlet.http.HttpServletResponse; 28 | import java.io.IOException; 29 | 30 | /** 31 | * A primitive authentication Servlet Filter. This is NOT a production ready application. It's goal is to demonstrate how to integrate Okta's Authentication SDK into an existing Servlet based framework. If you are starting from scratch we strongly recommend using OIDC/OAuth 2.0 via our Spring Boot integration or other OAuth 2.0 library. 32 | * 33 | * @see Okta Spring Samples 34 | * @see OWASP Top Ten Cheat Sheet 35 | */ 36 | public class OktaFilter implements Filter { 37 | 38 | static final String USER_SESSION_KEY = User.class.getName(); 39 | 40 | @Override 41 | public void init(FilterConfig filterConfig) {} 42 | 43 | @Override 44 | public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { 45 | 46 | HttpServletRequest request = (HttpServletRequest) req; 47 | HttpServletResponse response = (HttpServletResponse) resp; 48 | String path = request.getServletPath(); 49 | 50 | // allow anonymous access to static resources and anything under /authn/ and the root index.jsp 51 | if (isStaticAsset(request) || path.startsWith("/authn/") || path.equals("/index.jsp") || path.equals("/")) { 52 | chain.doFilter(request, response); 53 | return; 54 | } 55 | 56 | // check if we have a current user in the session 57 | if (isAuthenticated(request)) { 58 | chain.doFilter(request, response); 59 | return; 60 | } 61 | 62 | // no authenticated user found in session 63 | // redirect to /authn/login 64 | response.sendRedirect("/authn/login"); 65 | } 66 | 67 | @Override 68 | public void destroy() {} 69 | 70 | private boolean isAuthenticated(HttpServletRequest request) { 71 | return request.getSession(false) == null 72 | || request.getSession().getAttribute(USER_SESSION_KEY) != null; 73 | } 74 | 75 | private boolean isStaticAsset(HttpServletRequest request) { 76 | String path = request.getServletPath(); 77 | return path.startsWith("/static/") || path.equals("/favicon.ico"); 78 | } 79 | } -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/OverlySimpleCsrfFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples; 17 | 18 | import com.okta.commons.lang.Strings; 19 | 20 | import javax.servlet.Filter; 21 | import javax.servlet.FilterChain; 22 | import javax.servlet.FilterConfig; 23 | import javax.servlet.ServletException; 24 | import javax.servlet.ServletRequest; 25 | import javax.servlet.ServletResponse; 26 | import javax.servlet.http.HttpServletRequest; 27 | import javax.servlet.http.HttpServletResponse; 28 | import java.io.IOException; 29 | import java.util.Arrays; 30 | import java.util.HashSet; 31 | import java.util.Set; 32 | import java.util.UUID; 33 | 34 | /** 35 | * Simplistic CSRF filter 36 | */ 37 | public class OverlySimpleCsrfFilter implements Filter { 38 | 39 | private static final String CSRF_KEY = "_csrf"; 40 | private static final String CSRF_HEADER = "X-CSRF-TOKEN"; 41 | 42 | private final Set allowedMethods = new HashSet<>(Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS")); 43 | 44 | @Override 45 | public void init(FilterConfig filterConfig) {} 46 | 47 | @Override 48 | public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { 49 | 50 | HttpServletRequest request = (HttpServletRequest) req; 51 | HttpServletResponse response = (HttpServletResponse) resp; 52 | 53 | String expectedCsrf = (String) request.getSession().getAttribute(CSRF_KEY); 54 | 55 | // figure out the next CSRF token 56 | String nextCSRF = UUID.randomUUID().toString(); 57 | request.setAttribute(CSRF_KEY, nextCSRF); 58 | 59 | // add next csrf token to the session 60 | request.getSession().setAttribute(CSRF_KEY, nextCSRF); 61 | 62 | if (shouldFilter(request)) { 63 | 64 | String actualCsrf = request.getHeader(CSRF_HEADER); 65 | if (actualCsrf == null) { 66 | actualCsrf = request.getParameter(CSRF_KEY); 67 | } 68 | 69 | if (Strings.isEmpty(expectedCsrf) || !expectedCsrf.equals(actualCsrf)) { 70 | 71 | String errorMessage = "CSRF token did not match"; 72 | request.getServletContext().log(errorMessage); 73 | response.sendError(HttpServletResponse.SC_BAD_REQUEST, errorMessage); 74 | return; 75 | } 76 | } 77 | chain.doFilter(request, response); 78 | } 79 | 80 | @Override 81 | public void destroy() {} 82 | 83 | private boolean shouldFilter(HttpServletRequest request) { 84 | return !allowedMethods.contains(request.getMethod()); 85 | } 86 | } -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/UserProfileServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples; 17 | 18 | import com.okta.authn.sdk.resource.User; 19 | 20 | import javax.servlet.ServletException; 21 | import javax.servlet.annotation.WebServlet; 22 | import javax.servlet.http.HttpServlet; 23 | import javax.servlet.http.HttpServletRequest; 24 | import javax.servlet.http.HttpServletResponse; 25 | import java.io.IOException; 26 | 27 | /** 28 | * Simple example servlet that displays the current user's details. 29 | */ 30 | @WebServlet(name = "UserProfile", urlPatterns = {"/profile"}) 31 | public class UserProfileServlet extends HttpServlet { 32 | 33 | @Override 34 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 35 | // get the currently logged in user 36 | User user = (User) request.getSession(true).getAttribute(OktaFilter.USER_SESSION_KEY); 37 | 38 | // add the user to the request context and render the JSP 39 | request.setAttribute("user", user); 40 | // This has also been added the example JSPs directly using: 41 | // 42 | 43 | request.getRequestDispatcher("/WEB-INF/user-profile.jsp").forward(request, response); 44 | } 45 | } -------------------------------------------------------------------------------- /authn-servlet/src/main/java/com/okta/servlet/examples/models/Factor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples.models; 17 | 18 | import com.okta.sdk.resource.user.factor.FactorType; 19 | 20 | import java.util.Map; 21 | 22 | public class Factor { 23 | 24 | private String id; 25 | 26 | private String type; 27 | 28 | private String provider; 29 | 30 | private String vendorName; 31 | 32 | private String extraInfo; 33 | 34 | private Map profile; 35 | 36 | private String verifyHref; 37 | 38 | public Factor() {} 39 | 40 | public Factor(String id, String type, String provider, String vendorName, String extraInfo, Map profile, String verifyHref) { 41 | this.id = id; 42 | this.type = type; 43 | this.provider = provider; 44 | this.vendorName = vendorName; 45 | this.extraInfo = extraInfo; 46 | this.profile = profile; 47 | this.verifyHref = verifyHref; 48 | } 49 | 50 | public String getId() { 51 | return id; 52 | } 53 | 54 | public Factor setId(String id) { 55 | this.id = id; 56 | return this; 57 | } 58 | 59 | public String getType() { 60 | return type; 61 | } 62 | 63 | public Factor setType(String type) { 64 | this.type = type; 65 | return this; 66 | } 67 | 68 | public String getProvider() { 69 | return provider; 70 | } 71 | 72 | public Factor setProvider(String provider) { 73 | this.provider = provider; 74 | return this; 75 | } 76 | 77 | public String getVendorName() { 78 | return vendorName; 79 | } 80 | 81 | public Factor setVendorName(String vendorName) { 82 | this.vendorName = vendorName; 83 | return this; 84 | } 85 | 86 | public Map getProfile() { 87 | return profile; 88 | } 89 | 90 | public Factor setProfile(Map profile) { 91 | this.profile = profile; 92 | return this; 93 | } 94 | 95 | public String getVerifyHref() { 96 | return verifyHref; 97 | } 98 | 99 | public Factor setVerifyHref(String verifyHref) { 100 | this.verifyHref = verifyHref; 101 | return this; 102 | } 103 | 104 | public String getExtraInfo() { 105 | return extraInfo; 106 | } 107 | 108 | public Factor setExtraInfo(String extraInfo) { 109 | this.extraInfo = extraInfo; 110 | return this; 111 | } 112 | 113 | public static String relativeLink(com.okta.authn.sdk.resource.Factor factor) { 114 | FactorType type = factor.getType(); 115 | String templateName; 116 | switch (type) { 117 | case U2F: 118 | templateName = "u2f"; 119 | break; 120 | case TOKEN_SOFTWARE_TOTP: 121 | templateName = "totp"; 122 | break; 123 | case SMS: 124 | templateName = "sms"; 125 | break; 126 | default: 127 | templateName = "unknown"; 128 | } 129 | 130 | return templateName; 131 | } 132 | 133 | public static FactorType fromRelativeLink(String type) { 134 | FactorType oktaType; 135 | switch (type) { 136 | case "u2f": 137 | oktaType = FactorType.U2F; 138 | break; 139 | case "totp": 140 | oktaType = FactorType.TOKEN_SOFTWARE_TOTP; 141 | break; 142 | case "sms": 143 | oktaType = FactorType.SMS; 144 | break; 145 | default: 146 | oktaType = null; 147 | } 148 | return oktaType; 149 | } 150 | } -------------------------------------------------------------------------------- /authn-servlet/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 22 | 23 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/change-password.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

Your Password is no longer valid

28 |
29 |
30 | 31 | 32 | 33 |
34 |
35 |
36 | 37 |
38 |
39 | 40 |
41 |
42 | 43 |
44 | 45 | 46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/forgot-password.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

Password Recovery

28 |
29 |
30 | 31 |
32 |
33 |
34 | 35 |
36 | 45 | 46 | 47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/login.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 |
22 |
23 |
24 |
25 |
26 |

Please sign in

27 |
28 |
29 | 30 | 31 | 32 |
33 |
34 |
35 | 36 |
37 |
38 | 39 |
40 | 41 | 42 |
43 |
44 | Forgot Password? 45 |
46 |
47 |
48 |
49 |
50 | 51 | 52 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/mfa-required.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

MFA Required

28 |
29 | 41 |
42 |
43 |
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/mfa-verify-sms.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

MFA SMS Verify: ${factor.profile.phoneNumber}

28 |
29 |
30 | 31 |
"> 32 |
33 |
34 | 35 |
36 | 37 | 38 |
39 |
40 |
"> 41 | 42 | 43 | 44 |
45 |
46 |
47 |
48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/mfa-verify-totp.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

MFA TOTP Verify: ${factor.profile.credentialId}

28 |
29 |
30 | 31 |
32 |
33 |
34 | 35 |
36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/recovery.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

Recovery Question:

28 |
29 |
30 | 31 |
32 |
33 | ${question} 34 |
35 | 36 |
37 | 38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/reset-password.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

Reset your Password

28 |
29 |
30 | 31 |
32 |
33 |
34 | 35 |
36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/unlock-account.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

Unlock Account

28 |
29 |
30 | 31 |
32 |
33 |
34 | 35 |
36 | 45 | 46 | 47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | 55 | 56 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/unlock-recovery.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

Password Recovery Challenge:

28 |
29 |
30 | 31 |
32 |
33 |
34 | 35 |
36 | 37 | 38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/authn/unsupported-state.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |

Unsupported State

28 |
29 |
30 | This sample application does not support the state ${unsupportedState}. 31 |
32 |
33 |
34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/home.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Okta Authentication SDK + Servlet

27 | 28 | 29 |
30 |

Hello!

31 |

If you're viewing this page then you have successfully configured and started this example server.

32 |

This example shows you how to use the Okta 33 | Authentication SDK configured for a basic Servlet application.

34 | 35 | 52 |
53 | 54 |
"> 55 | 56 |
57 |
58 | 59 | 60 |
61 |

Welcome home, ${user.getFirstName()} ${user.getLastName()}!

62 |

You have successfully authenticated against your Okta org, and have been redirected back to this 63 | application.

64 |

Visit the ">My Profile page in this application to view your user's details.

65 |
66 |
67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/includes/csrf.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/includes/footer.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | <%-- 19 | Copyright 2019-Present Okta, Inc. 20 | 21 | Licensed under the Apache License, Version 2.0 (the "License"); 22 | you may not use this file except in compliance with the License. 23 | You may obtain a copy of the License at 24 | 25 | http://www.apache.org/licenses/LICENSE-2.0 26 | 27 | Unless required by applicable law or agreed to in writing, software 28 | distributed under the License is distributed on an "AS IS" BASIS, 29 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 | See the License for the specific language governing permissions and 31 | limitations under the License. 32 | --%> 33 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/includes/form-errors.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 19 | 20 | 21 | 37 | 38 | 39 | 40 | 44 | 45 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/includes/header.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | <%-- 19 | Copyright 2019-Present Okta, Inc. 20 | 21 | Licensed under the Apache License, Version 2.0 (the "License"); 22 | you may not use this file except in compliance with the License. 23 | You may obtain a copy of the License at 24 | 25 | http://www.apache.org/licenses/LICENSE-2.0 26 | 27 | Unless required by applicable law or agreed to in writing, software 28 | distributed under the License is distributed on an "AS IS" BASIS, 29 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 | See the License for the specific language governing permissions and 31 | limitations under the License. 32 | --%> 33 | 34 | 35 | 36 | 37 | 38 | Okta AuthN SDK (Java) Example 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/includes/menu.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 19 | 20 | 21 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/WEB-INF/user-profile.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | 19 | <%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %> 20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 |

My Profile

28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 |
KeyValue
${item.key}${item.value}
46 |
47 | 48 | 49 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%-- 2 | 3 | ~ Copyright 2019-Present Okta, Inc. 4 | ~ 5 | ~ Licensed under the Apache License, Version 2.0 (the "License"); 6 | ~ you may not use this file except in compliance with the License. 7 | ~ You may obtain a copy of the License at 8 | ~ 9 | ~ http://www.apache.org/licenses/LICENSE-2.0 10 | ~ 11 | ~ Unless required by applicable law or agreed to in writing, software 12 | ~ distributed under the License is distributed on an "AS IS" BASIS, 13 | ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ~ See the License for the specific language governing permissions and 15 | ~ limitations under the License. 16 | 17 | --%> 18 | <%-- 19 | Copyright 2019-Present Okta, Inc. 20 | 21 | Licensed under the Apache License, Version 2.0 (the "License"); 22 | you may not use this file except in compliance with the License. 23 | You may obtain a copy of the License at 24 | 25 | http://www.apache.org/licenses/LICENSE-2.0 26 | 27 | Unless required by applicable law or agreed to in writing, software 28 | distributed under the License is distributed on an "AS IS" BASIS, 29 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 | See the License for the specific language governing permissions and 31 | limitations under the License. 32 | --%> 33 | -------------------------------------------------------------------------------- /authn-servlet/src/main/webapp/static/css/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | .vertical-offset-100 { 17 | padding-top:100px; 18 | } 19 | 20 | .demo-mfa-icon-totp:before { 21 | content: "\e033"; 22 | } 23 | 24 | .demo-mfa-icon-u2f:before { 25 | content: "\e033"; 26 | } 27 | 28 | .demo-mfa-icon-sms:before { 29 | content: "\e145"; 30 | } -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | ########################################################################################## 204 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 205 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 206 | ########################################################################################## 207 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 208 | if [ "$MVNW_VERBOSE" = true ]; then 209 | echo "Found .mvn/wrapper/maven-wrapper.jar" 210 | fi 211 | else 212 | if [ "$MVNW_VERBOSE" = true ]; then 213 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 214 | fi 215 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar" 216 | while IFS="=" read key value; do 217 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 218 | esac 219 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Downloading from: $jarUrl" 222 | fi 223 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 224 | 225 | if command -v wget > /dev/null; then 226 | if [ "$MVNW_VERBOSE" = true ]; then 227 | echo "Found wget ... using wget" 228 | fi 229 | wget "$jarUrl" -O "$wrapperJarPath" 230 | elif command -v curl > /dev/null; then 231 | if [ "$MVNW_VERBOSE" = true ]; then 232 | echo "Found curl ... using curl" 233 | fi 234 | curl -o "$wrapperJarPath" "$jarUrl" 235 | else 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Falling back to using Java to download" 238 | fi 239 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 240 | if [ -e "$javaClass" ]; then 241 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 242 | if [ "$MVNW_VERBOSE" = true ]; then 243 | echo " - Compiling MavenWrapperDownloader.java ..." 244 | fi 245 | # Compiling the Java class 246 | ("$JAVA_HOME/bin/javac" "$javaClass") 247 | fi 248 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 249 | # Running the downloader 250 | if [ "$MVNW_VERBOSE" = true ]; then 251 | echo " - Running MavenWrapperDownloader.java ..." 252 | fi 253 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 254 | fi 255 | fi 256 | fi 257 | fi 258 | ########################################################################################## 259 | # End of extension 260 | ########################################################################################## 261 | 262 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo $MAVEN_PROJECTBASEDIR 265 | fi 266 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 267 | 268 | # For Cygwin, switch paths to Windows format before running java 269 | if $cygwin; then 270 | [ -n "$M2_HOME" ] && 271 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 272 | [ -n "$JAVA_HOME" ] && 273 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 274 | [ -n "$CLASSPATH" ] && 275 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 276 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 277 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 278 | fi 279 | 280 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 281 | 282 | exec "$JAVACMD" \ 283 | $MAVEN_OPTS \ 284 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 285 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 286 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 287 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.0/maven-wrapper-0.4.0.jar" 124 | FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( 125 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 126 | ) 127 | 128 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 129 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 130 | if exist %WRAPPER_JAR% ( 131 | echo Found %WRAPPER_JAR% 132 | ) else ( 133 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 134 | echo Downloading from: %DOWNLOAD_URL% 135 | powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" 136 | echo Finished downloading %WRAPPER_JAR% 137 | ) 138 | @REM End of extension 139 | 140 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 141 | if ERRORLEVEL 1 goto error 142 | goto end 143 | 144 | :error 145 | set ERROR_CODE=1 146 | 147 | :end 148 | @endlocal & set ERROR_CODE=%ERROR_CODE% 149 | 150 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 151 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 152 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 153 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 154 | :skipRcPost 155 | 156 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 157 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 158 | 159 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 160 | 161 | exit /B %ERROR_CODE% 162 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 4.0.0 20 | 21 | com.okta.servlet.examples 22 | servlet-aggregator 23 | 1-SNAPSHOT 24 | Okta Servlet Samples :: Aggregator 25 | See README for details. 26 | pom 27 | 28 | 29 | authn-servlet 30 | resource-server 31 | 32 | 33 | 34 | 35 | 36 | com.mycila 37 | license-maven-plugin 38 | 4.2 39 | 40 | 41 | com.okta 42 | okta-parent-build-support 43 | 14 44 | 45 | 46 | 47 | true 48 | true 49 |
license/header.txt
50 | 51 | license/header_format.xml 52 | 53 | 54 | Okta 55 | 2019 56 | 57 | 58 | **/*.txt 59 | 60 |
61 |
62 |
63 |
64 |
65 | -------------------------------------------------------------------------------- /resource-server/README.md: -------------------------------------------------------------------------------- 1 | # Okta Resource Server Example 2 | 3 | This sample application authenticates requests, using an OAuth 2.0 access tokens and [Okta JWT Verifier for Java][] 4 | 5 | The access tokens are obtained via the [Implicit Flow][]. One easy way to obtain an access token is to use the [OpenID Connect Debugger][]. Take a look at this [blog post][]. 6 | 7 | ## Prerequisites 8 | 9 | Before running this sample, you will need the following: 10 | 11 | * An Okta Developer Account, you can sign up for one at https://developer.okta.com/signup/. 12 | * An access token, obtained with the [OpenID Connect Debugger][] (instructions via this [blog post][]) 13 | 14 | ## Running This Example 15 | 16 | ```bash 17 | cd resource-server 18 | mvn -Dokta.oauth2.issuer=https://{yourOktaDomain}/oauth2/default 19 | ``` 20 | 21 | ## Access the resource 22 | 23 | ```bash 24 | curl http://localhost:8000/api/messages 25 | 26 | > GET /api/messages HTTP/1.1 27 | > Host: localhost:8000 28 | > User-Agent: curl/7.54.0 29 | > Accept: */* 30 | > 31 | < HTTP/1.1 401 Unauthorized 32 | < WWW-Authenticate: Bearer realm=Okta 33 | ``` 34 | 35 | Try again with an access token: 36 | 37 | ```bash 38 | 39 | curl http://localhost:8000/api/messages -H"Authorization: Bearer ${accessToken}" 40 | 41 | < HTTP/1.1 200 OK 42 | < Date: Wed, 27 Feb 2019 16:55:55 GMT 43 | < Content-Type: application/json 44 | 45 | { 46 | "messages": [ 47 | { 48 | "date": "2019-02-27T16:55:42.740+0000", 49 | "text": "I am a robot." 50 | }, 51 | { 52 | "date": "2019-02-27T16:55:42.740+0000", 53 | "text": "Hello, world!" 54 | } 55 | ] 56 | } 57 | ``` 58 | 59 | [Implicit Flow]: https://developer.okta.com/authentication-guide/implementing-authentication/implicit 60 | [Okta JWT Verifier for Java]: https://github.com/okta/okta-jwt-verifier-java 61 | [OpenID Connect Debugger]: https://oidcdebugger.com/ 62 | [blog post]: https://developer.okta.com/blog/2018/12/18/secure-spring-rest-api#generate-tokens-in-your-spring-rest-api -------------------------------------------------------------------------------- /resource-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 4.0.0 20 | 21 | com.okta.servlet.examples 22 | resource-server 23 | 1-SNAPSHOT 24 | Okta Servlet Samples :: Basic OAuth 2.0 Resource Server 25 | See README for details. 26 | 27 | 28 | UTF-8 29 | 12.0.12 30 | 31 | 32 | 33 | 34 | 35 | com.okta.jwt 36 | okta-jwt-verifier 37 | 0.5.8 38 | 39 | 40 | com.okta.jwt 41 | okta-jwt-verifier-impl 42 | 0.5.8 43 | runtime 44 | 45 | 46 | 47 | com.fasterxml.jackson.core 48 | jackson-databind 49 | 2.15.1 50 | 51 | 52 | 53 | org.eclipse.jetty 54 | jetty-annotations 55 | ${jetty.version} 56 | 57 | 58 | org.eclipse.jetty 59 | jetty-server 60 | ${jetty.version} 61 | 62 | 63 | org.eclipse.jetty 64 | jetty-webapp 65 | ${jetty.version} 66 | 67 | 68 | org.eclipse.jetty 69 | jetty-xml 70 | 10.0.16 71 | 72 | 73 | javax.servlet 74 | javax.servlet-api 75 | 3.1.0 76 | 77 | 78 | 79 | ch.qos.logback 80 | logback-classic 81 | 1.4.14 82 | runtime 83 | 84 | 85 | ch.qos.logback 86 | logback-core 87 | 1.4.14 88 | 89 | 90 | 91 | 92 | com.okta.oidc.tck 93 | okta-oidc-tck 94 | 0.5.9 95 | test 96 | 97 | 98 | 99 | commons-codec 100 | commons-codec 101 | 1.16.0 102 | 103 | 104 | 105 | 106 | compile exec:java 107 | 108 | 109 | maven-compiler-plugin 110 | 3.11.0 111 | 112 | 1.8 113 | 1.8 114 | 115 | 116 | 117 | org.codehaus.mojo 118 | exec-maven-plugin 119 | 3.1.0 120 | 121 | 122 | 123 | java 124 | 125 | 126 | 127 | 128 | com.okta.servlet.examples.resourceserver.ResourceServerApplication 129 | 130 | 131 | 132 | 133 | org.apache.maven.plugins 134 | maven-dependency-plugin 135 | 3.6.0 136 | 137 | 138 | 139 | unpack 140 | 141 | 142 | 143 | 144 | 145 | 146 | com.okta.oidc.tck 147 | okta-oidc-tck 148 | ${project.build.directory} 149 | tck-keystore.jks 150 | tck-keystore.jks 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /resource-server/src/main/java/com/okta/servlet/examples/resourceserver/AccessUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples.resourceserver; 17 | 18 | import com.okta.jwt.Jwt; 19 | 20 | import java.util.List; 21 | 22 | final class AccessUtil { 23 | 24 | private AccessUtil() {} 25 | 26 | static boolean hasScope(String scope, Jwt accessToken) { 27 | 28 | if (accessToken != null) { 29 | List scopes = (List) accessToken.getClaims().get("scp"); 30 | return scopes != null && scopes.contains(scope); 31 | } 32 | return false; 33 | } 34 | } -------------------------------------------------------------------------------- /resource-server/src/main/java/com/okta/servlet/examples/resourceserver/MessagesServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples.resourceserver; 17 | 18 | import com.fasterxml.jackson.databind.ObjectMapper; 19 | import com.fasterxml.jackson.databind.SerializationFeature; 20 | import com.okta.jwt.Jwt; 21 | 22 | import javax.servlet.ServletConfig; 23 | import javax.servlet.ServletException; 24 | import javax.servlet.annotation.WebServlet; 25 | import javax.servlet.http.HttpServlet; 26 | import javax.servlet.http.HttpServletRequest; 27 | import javax.servlet.http.HttpServletResponse; 28 | import java.io.IOException; 29 | import java.util.Arrays; 30 | import java.util.Date; 31 | import java.util.HashMap; 32 | import java.util.Map; 33 | 34 | /** 35 | * Simple example hello world servlet. 36 | */ 37 | @WebServlet(name = "MessagesServlet", urlPatterns = {"/api/messages"}) 38 | public class MessagesServlet extends HttpServlet { 39 | 40 | private ObjectMapper objectMapper; 41 | 42 | @Override 43 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 44 | 45 | // only return the claims if this token has the "email" scope 46 | if (AccessUtil.hasScope("email", (Jwt) request.getAttribute("accessToken"))) { 47 | respondWithMessages(response); 48 | } else { 49 | response.sendError(403, "Unauthorized"); 50 | } 51 | } 52 | 53 | private void respondWithMessages(HttpServletResponse response) throws IOException { 54 | Map messages = new HashMap<>(); 55 | messages.put("messages", Arrays.asList( 56 | new Message("I am a robot."), 57 | new Message("Hello, world!") 58 | )); 59 | 60 | response.setStatus(200); 61 | response.addHeader("Content-Type", "application/json"); 62 | objectMapper.writeValue(response.getOutputStream(), messages); 63 | } 64 | 65 | class Message { 66 | public Date date = new Date(); 67 | public String text; 68 | 69 | Message(String text) { 70 | this.text = text; 71 | } 72 | } 73 | 74 | @Override 75 | public void init(ServletConfig config) throws ServletException { 76 | super.init(config); 77 | objectMapper = new ObjectMapper().disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 78 | } 79 | 80 | @Override 81 | public void destroy() { 82 | super.destroy(); 83 | objectMapper = null; 84 | } 85 | } -------------------------------------------------------------------------------- /resource-server/src/main/java/com/okta/servlet/examples/resourceserver/OktaBearerFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples.resourceserver; 17 | 18 | import com.okta.jwt.AccessTokenVerifier; 19 | import com.okta.jwt.Jwt; 20 | import com.okta.jwt.JwtVerificationException; 21 | import com.okta.jwt.JwtVerifiers; 22 | 23 | import javax.servlet.Filter; 24 | import javax.servlet.FilterChain; 25 | import javax.servlet.FilterConfig; 26 | import javax.servlet.ServletException; 27 | import javax.servlet.ServletRequest; 28 | import javax.servlet.ServletResponse; 29 | import javax.servlet.annotation.WebFilter; 30 | import javax.servlet.http.HttpServletRequest; 31 | import javax.servlet.http.HttpServletResponse; 32 | import java.io.IOException; 33 | import java.util.StringTokenizer; 34 | 35 | @WebFilter(urlPatterns = "/*") 36 | public class OktaBearerFilter implements Filter { 37 | 38 | AccessTokenVerifier verifier = null; 39 | 40 | @Override 41 | public void init(FilterConfig filterConfig) throws ServletException { 42 | 43 | verifier = JwtVerifiers.accessTokenVerifierBuilder() 44 | .setIssuer(getIssuer(filterConfig)) // https://{yourOktaDomain}/oauth2/default 45 | .build(); 46 | } 47 | 48 | @Override 49 | public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 50 | 51 | HttpServletRequest request = (HttpServletRequest) req; 52 | HttpServletResponse response = (HttpServletResponse) res; 53 | 54 | // 1. grab the Authorization header 55 | String authHeader = request.getHeader("Authorization"); 56 | if( authHeader != null) { 57 | 58 | // 2. it must be in the format of 59 | StringTokenizer tokenizer = new StringTokenizer(authHeader); 60 | if (tokenizer.countTokens() == 2) { 61 | String type = tokenizer.nextToken(); 62 | String accessToken = tokenizer.nextToken(); 63 | 64 | // 3. make sure this is a "Bearer" token 65 | if ("Bearer".equals(type)) { 66 | try { 67 | 68 | // 4. validate access token 69 | // only valid JWT access tokens will be returned 70 | Jwt jwt = validateAccessToken(accessToken); 71 | 72 | // set a request attribute so we can get this data from a servlet 73 | request.setAttribute("accessToken", jwt); 74 | 75 | // continue 76 | chain.doFilter(request, response); 77 | } catch (JwtVerificationException e) { 78 | request.getServletContext().log("Invalid access token", e); 79 | } 80 | } else { 81 | request.getServletContext().log("Unsupported Authorization type"); 82 | } 83 | 84 | } else { 85 | request.getServletContext().log("Invalid Authorization header format"); 86 | } 87 | 88 | } 89 | // return 401 90 | authorizationFailure(response); 91 | } 92 | 93 | @Override 94 | public void destroy() { 95 | verifier = null; 96 | } 97 | 98 | private Jwt validateAccessToken(String token) throws JwtVerificationException { 99 | return verifier.decode(token); 100 | } 101 | 102 | private void authorizationFailure(HttpServletResponse response) throws IOException { 103 | response.setHeader("WWW-Authenticate", "Bearer realm=Okta"); 104 | response.sendError(401, "Unauthorized"); 105 | } 106 | 107 | private String getIssuer(FilterConfig filterConfig) { 108 | 109 | // 1. try filter config 110 | String issuer = filterConfig.getInitParameter("okta.oauth2.issuer"); 111 | 112 | // 2. try System Property 113 | if (issuer == null) { 114 | issuer = System.getProperty("okta.oauth2.issuer"); 115 | } 116 | 117 | // 2. try Env var 118 | if (issuer == null) { 119 | issuer = System.getenv("OKTA_OAUTH2_ISSUER"); 120 | } 121 | 122 | // returning null will result in a useful validation message from the verifier 123 | return issuer; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /resource-server/src/main/java/com/okta/servlet/examples/resourceserver/ProfileServlet.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples.resourceserver; 17 | 18 | import com.fasterxml.jackson.databind.ObjectMapper; 19 | import com.fasterxml.jackson.databind.SerializationFeature; 20 | import com.okta.jwt.Jwt; 21 | 22 | import javax.servlet.ServletConfig; 23 | import javax.servlet.ServletException; 24 | import javax.servlet.annotation.WebServlet; 25 | import javax.servlet.http.HttpServlet; 26 | import javax.servlet.http.HttpServletRequest; 27 | import javax.servlet.http.HttpServletResponse; 28 | import java.io.IOException; 29 | 30 | /** 31 | * Simple example servlet that displays the current user's details. 32 | */ 33 | @WebServlet(name = "ProfileServlet", urlPatterns = {"/api/userProfile"}) 34 | public class ProfileServlet extends HttpServlet { 35 | 36 | private ObjectMapper objectMapper; 37 | 38 | @Override 39 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 40 | 41 | Jwt accessToken = (Jwt) request.getAttribute("accessToken"); 42 | 43 | // only return the claims if this token has the "profile" scope 44 | if (AccessUtil.hasScope("profile", accessToken)) { 45 | 46 | response.setStatus(200); 47 | response.addHeader("Content-Type", "application/json"); 48 | objectMapper.writeValue(response.getOutputStream(), accessToken.getClaims()); 49 | 50 | } else { 51 | response.sendError(403, "Unauthorized"); 52 | } 53 | } 54 | 55 | 56 | @Override 57 | public void init(ServletConfig config) throws ServletException { 58 | super.init(config); 59 | objectMapper = new ObjectMapper().disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 60 | } 61 | 62 | @Override 63 | public void destroy() { 64 | super.destroy(); 65 | objectMapper = null; 66 | } 67 | } -------------------------------------------------------------------------------- /resource-server/src/main/java/com/okta/servlet/examples/resourceserver/ResourceServerApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019-Present Okta, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.okta.servlet.examples.resourceserver; 17 | 18 | import org.eclipse.jetty.annotations.AnnotationConfiguration; 19 | import org.eclipse.jetty.server.Server; 20 | import org.eclipse.jetty.util.resource.Resource; 21 | import org.eclipse.jetty.webapp.Configuration; 22 | import org.eclipse.jetty.webapp.WebAppContext; 23 | import org.eclipse.jetty.webapp.WebInfConfiguration; 24 | import org.eclipse.jetty.webapp.WebXmlConfiguration; 25 | 26 | import java.io.File; 27 | 28 | /** 29 | * Simple embedded web application to make running this sample easier. Servlet and Filter are registered 30 | * via annotations and should work in a traditional WAR file app the same way. 31 | */ 32 | public class ResourceServerApplication { 33 | 34 | public static void main(String[] args) throws Exception { 35 | 36 | WebAppContext webapp = new WebAppContext(); 37 | webapp.setBaseResource(Resource.newResource(new File( "src/main/webapp"))); 38 | webapp.setContextPath("/"); 39 | webapp.setWelcomeFiles(new String[]{"/"}); 40 | webapp.setParentLoaderPriority(true); 41 | webapp.setConfigurations(new Configuration[] { 42 | new AnnotationConfiguration(), 43 | new WebInfConfiguration(), 44 | new WebXmlConfiguration() 45 | }); 46 | 47 | // scan everything for annotations, jstl, web fragments, etc 48 | webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*"); 49 | 50 | int port = Integer.parseInt(System.getProperty("server.port")); 51 | Server server = new Server(port); 52 | server.setHandler(webapp); 53 | server.start(); 54 | System.out.println("Web app started: http://localhost:" + port + "/"); 55 | server.join(); 56 | } 57 | } -------------------------------------------------------------------------------- /resource-server/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | 22 | 23 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /resource-server/src/test/resources/testRunner.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2017 Okta, Inc. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | scenarios: 17 | implicit-flow-local-validation: 18 | command: mvn 19 | args: 20 | - -Dserver.port=${applicationPort} 21 | - -Dokta.oauth2.issuer=https://localhost:${mockHttpsPort}/oauth2/default 22 | - -Dokta.oauth2.clientId=OOICU812 23 | - -Djavax.net.ssl.trustStore=target/tck-keystore.jks 24 | - --batch-mode 25 | --------------------------------------------------------------------------------