summaryrefslogtreecommitdiffstats
path: root/simple/simple-http/src/main/java/org/simpleframework/http/parse/PrincipalParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'simple/simple-http/src/main/java/org/simpleframework/http/parse/PrincipalParser.java')
-rw-r--r--simple/simple-http/src/main/java/org/simpleframework/http/parse/PrincipalParser.java362
1 files changed, 362 insertions, 0 deletions
diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/parse/PrincipalParser.java b/simple/simple-http/src/main/java/org/simpleframework/http/parse/PrincipalParser.java
new file mode 100644
index 0000000..52aeff8
--- /dev/null
+++ b/simple/simple-http/src/main/java/org/simpleframework/http/parse/PrincipalParser.java
@@ -0,0 +1,362 @@
+/*
+ * PrincipalParser.java February 2001
+ *
+ * Copyright (C) 2001, Niall Gallagher <niallg@users.sf.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package org.simpleframework.http.parse;
+
+import org.simpleframework.common.parse.ParseBuffer;
+import org.simpleframework.common.parse.Parser;
+import org.simpleframework.http.Principal;
+
+/**
+ * PrincipalParser is a parser class for the HTTP basic authorization
+ * header. It decodes the <code>base64</code> encoding of the user and
+ * password pair.
+ * <p>
+ * This follows the parsing tree of RFC 2617. The goal of this parser
+ * is to decode the <code>base64</code> encoding of the user name and
+ * password. After the string has been decoded then the user name and
+ * password are extracted. This will only parse headers that are from
+ * the <code>Basic</code> authorization scheme. The format of the basic
+ * scheme can be found in RFC 2617 and is of the form
+ * <pre>
+ * Basic SP base64-encoding.
+ * </pre>
+ *
+ * @author Niall Gallagher
+ */
+public class PrincipalParser extends Parser implements Principal {
+
+ /**
+ * Keeps the characters consumed for the password token.
+ */
+ private ParseBuffer password;
+
+ /**
+ * Keeps the characters consumed for the user name token.
+ */
+ private ParseBuffer user;
+
+ /**
+ * Keeps the <code>bytes</code> used for decoding base64.
+ */
+ private byte[] four;
+
+ /**
+ * Tracks the write offset for the buffer.
+ */
+ private int write;
+
+ /**
+ * Tracks the ready offset for the four buffer.
+ */
+ private int ready;
+
+ /**
+ * Tracks the read offset for the buffer.
+ */
+ private int read;
+
+ /**
+ * Creates a <code>Parser</code> for the basic authorization
+ * scheme. This allows headers that are of this scheme to be
+ * broken into its component parts i.e. user name and password.
+ */
+ public PrincipalParser() {
+ this.password = new ParseBuffer();
+ this.user = new ParseBuffer();
+ this.four = new byte[4];
+ }
+
+ /**
+ * Creates a <code>Parser</code> for the basic authorization
+ * scheme. This allows headers that are of this scheme to be
+ * broken into its component parts i.e. user name and password.
+ * This constructor will parse the <code>String</code> given as
+ * the header.
+ *
+ * @param header this is a header value from the basic scheme
+ */
+ public PrincipalParser(String header){
+ this();
+ parse(header);
+ }
+
+ /**
+ * Gets the users password parsed from the Authorization
+ * header value. If there was not password parsed from the
+ * base64 value of the header this returns <code>null</code>
+ *
+ * @return the password for the user or <code>null</code>
+ */
+ public String getPassword(){
+ if(password.length() == 0){
+ return null;
+ }
+ return password.toString();
+ }
+
+ /**
+ * Gets the users name from the Authorization header value.
+ * This will return <code>null</code> if there is no user
+ * name extracted from the base64 header value.
+ *
+ * @return this returns the name of the user
+ */
+ public String getName(){
+ if(user.length() == 0){
+ return null;
+ }
+ return user.toString();
+ }
+
+ /**
+ * Used to parse the actual header data. This will attempt to
+ * read the "Basic" token from the set of characters given, if
+ * this is successful then the username and password is
+ * extracted.
+ */
+ protected void parse(){
+ if(skip("Basic ")){
+ decode();
+ userpass();
+ }
+ }
+
+ /**
+ * This will initialize the <code>Parser</code> when it is ready
+ * to parse a new <code>String</code>. This will reset the
+ * <code>Parser</code> to a ready state. The <code>init</code> method
+ * is invoked by the <code>Parser</code> when the <code>parse</code>
+ * method is invoked.
+ */
+ protected void init() {
+ password.clear();
+ user.clear();
+ write = ready =
+ read = off = 0;
+ pack();
+ }
+
+ /**
+ * This is used to remove all whitespace characters from the
+ * <code>String</code> excluding the whitespace within literals.
+ * The definition of a literal can be found in RFC 2616.
+ * <p>
+ * The definition of a literal for RFC 2616 is anything between 2
+ * quotes but excuding quotes that are prefixed with the backward
+ * slash character.
+ */
+ private void pack() {
+ int len = count;
+ int seek = 0; /* read */
+ int pos = 0; /* write */
+ char ch = 0;
+
+ while(seek <len){ /* trim start*/
+ if(!space(buf[seek])){
+ break;
+ }
+ seek++;
+ }
+ while(seek < len){
+ ch = buf[seek++];
+ if(space(ch)){
+ while(seek < len){ /* skip spaces */
+ if(!space(buf[seek])){
+ break;
+ }
+ seek++;
+ }
+ }
+ buf[pos++] = ch;
+ }
+ if(space(ch)){ /* trim end */
+ pos--;
+ }
+ count = pos;
+ }
+
+ /**
+ * Extracts the name and password of the user from the
+ * <code>name : password</code> pair that was given. This
+ * will take all data up to the first occurence of a
+ * ':' character as the users name and all data after the
+ * colon as the users password.
+ */
+ private void userpass(){
+ userid();
+ off++;
+ password();
+ }
+
+ /**
+ * Extracts the user name from the buffer. This will read up to
+ * the first occurence of a colon, ':', character as the user
+ * name. For the BNF syntax of this see RFC 2617.
+ */
+ private void userid(){
+ while(off < count){
+ char ch = buf[off];
+ if(!text(ch) || ch ==':'){
+ break;
+ }
+ user.append(ch);
+ off++;
+ }
+
+ }
+
+ /**
+ * Extracts the password from the buffer. This will all characters
+ * from the current offset to the first non text character as the
+ * password. For the BNF syntax of this see RFC 2617.
+ */
+ private void password() {
+ while(off < count){
+ char ch = buf[off];
+ if(!text(ch)){
+ break;
+ }
+ password.append(ch);
+ off++;
+ }
+ }
+
+ /**
+ * This is used to remove decode the <code>base64</code> encoding of
+ * the user name and password. This uses a standart <code>base64</code>
+ * decoding scheme.
+ * <p>
+ * For information on the decoding scheme used for <code>base64</code>
+ * see the RFC 2045 on MIME, Multipurpose Internet Mail Extensions.
+ */
+ private void decode() {
+ for(write = read = off; read + 3 < count;) {
+ while(ready < 4) {
+ int ch = translate(buf[read++]);
+ if(ch >= 0) {
+ four[ready++] = (byte)ch;
+ }
+ }
+ if(four[2] == 65) {
+ buf[write++] = first(four);
+ break;
+ } else if(four[3] == 65) {
+ buf[write++] = first(four);
+ buf[write++] = second(four);
+ break;
+ } else {
+ buf[write++] = first(four);
+ buf[write++] = second(four);
+ buf[write++] = third(four);
+ }
+ ready = 0;
+ }
+ count = write;
+ }
+
+ /**
+ * This uses a basic translation from the <code>byte</code> character to the
+ * <code>byte</code> number.
+ * <p>
+ * The table for translation the data can be found in RFC 2045 on
+ * MIME, Multipurpose Internet Mail Extensions.
+ *
+ * @param octet this is the octet ttat is to be translated
+ *
+ * @return this returns the translated octet
+ */
+ private int translate(int octet) {
+ if(octet >= 'A' && octet <= 'Z') {
+ octet = octet - 'A';
+ } else if(octet >= 'a' && octet <= 'z') {
+ octet = (octet - 'a') + 26;
+ } else if(octet >= '0' && octet <= '9') {
+ octet = (octet - '0') + 52;
+ } else if(octet == '+') {
+ octet = 62;
+ } else if(octet == '/') {
+ octet = 63;
+ } else if(octet == '=') {
+ octet = 65;
+ } else {
+ octet = -1;
+ }
+ return octet;
+ }
+
+ /**
+ * This is used to extract the <code>byte</code> from the set of four
+ * <code>bytes</code> given. This method is used to isolate the correct
+ * bits that corrospond to an actual character withing the
+ * <code>base64</code> data.
+ *
+ * @param four this is the four <code>bytes</code> that the character
+ * is to be extracted from
+ *
+ * @return this returns the character extracted
+ */
+ private char first(byte[] four) {
+ return (char)(((four[0] & 0x3f) << 2) | ((four[1] & 0x30) >>> 4));
+ }
+
+ /**
+ * This is used to extract the <code>byte</code> from the set of four
+ * <code>bytes</code> given. This method is used to isolate the correct
+ * bits that corrospond to an actual character withing the
+ * <code>base64</code> data.
+ *
+ * @param four this is the four <code>bytes</code> that the character
+ * is to be extracted from
+ *
+ * @return this returns the character extracted
+
+ */
+ private char second(byte[] four) {
+ return (char)(((four[1] & 0x0f) << 4) | ((four[2] &0x3c) >>> 2));
+ }
+
+ /**
+ * This is used to extract the <code>byte</code> from the set of four
+ * <code>bytes</code> given. This method is used to isolate the correct
+ * bits that corrospond to an actual character withing the
+ * <code>base64</code> data.
+ *
+ * @param four this is the four <code>bytes</code> that the character
+ * is to be extracted from
+ *
+ * @return this returns the character extracted
+ */
+ private char third(byte[] four) {
+ return (char)(((four[2] & 0x03) << 6) | (four[3] & 0x3f));
+ }
+
+ /**
+ * This is used to determine wheather or not a character is a
+ * <code>TEXT</code> character according to the HTTP specification,
+ * that is RFC 2616 specifies a <code>TEXT</code> character as one
+ * that is any octet except those less than 32 and not 127.
+ *
+ * @param c this is the character that is to be determined
+ *
+ * @return this returns true if the character is a <code>TEXT</code>
+ */
+ private boolean text(char c){
+ return c > 31 && c != 127 && c <= 0xffff;
+ }
+}